# HG changeset patch # User mikael # Date 1588806530 25200 # Wed May 06 16:08:50 2020 -0700 # Node ID 45db31fcc7e6f98e00ae7dae2296437330a380ab # Parent f03eda8f2e199b1bb33ca219c8126edc6d3176b7 imported patch hotspot diff --git a/src/hotspot/.mx.jvmci/mx_jvmci.py b/src/hotspot/.mx.jvmci/mx_jvmci.py --- a/src/hotspot/.mx.jvmci/mx_jvmci.py +++ b/src/hotspot/.mx.jvmci/mx_jvmci.py @@ -387,7 +387,7 @@ if t: _runmultimake(['--jdk-jvm-variants', 'server', '--jdk-debug-levels', 'fastdebug']) with Task('CleanAndBuildIdealGraphVisualizer', tasks, disableJacoco=True) as t: - if t and platform.processor() != 'sparc': + if t: buildxml = mx._cygpathU2W(join(_suite.dir, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml')) mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=_igvBuildEnv()) @@ -486,8 +486,6 @@ flavor = 'intel' if 'att' in args: flavor = 'att' - if mx.get_arch() == "sparcv9": - flavor = "sparcv9" lib = mx.add_lib_suffix('hsdis-' + mx.get_arch()) path = join(_suite.dir, 'lib', lib) @@ -497,7 +495,6 @@ 'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30', 'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192', 'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2', - 'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60', } flavoredLib = flavor + "/" + lib @@ -579,8 +576,6 @@ os = 'macosx' elif 'linux' in os: os = 'linux' - elif 'solaris' in os: - os = 'solaris' elif 'cygwin' in os or 'mingw' in os: os = 'windows' return os @@ -589,8 +584,6 @@ cpu = mx.get_arch() if cpu == 'amd64': cpu = 'x86_64' - elif cpu == 'sparcv9': - cpu = 'sparcv9' return cpu def _get_openjdk_os_cpu(): diff --git a/src/hotspot/.mx.jvmci/suite.py b/src/hotspot/.mx.jvmci/suite.py --- a/src/hotspot/.mx.jvmci/suite.py +++ b/src/hotspot/.mx.jvmci/suite.py @@ -87,7 +87,6 @@ "dependencies" : [ "mx:JUNIT", "jdk.vm.ci.amd64", - "jdk.vm.ci.sparc", "jdk.vm.ci.code", "jdk.vm.ci.hotspot", ], @@ -141,15 +140,6 @@ "workingSets" : "JVMCI,AMD64", }, - "jdk.vm.ci.sparc" : { - "subDir" : "../jdk.internal.vm.ci/share/classes", - "sourceDirs" : ["src"], - "dependencies" : ["jdk.vm.ci.code"], - "checkstyle" : "jdk.vm.ci.services", - "javaCompliance" : "9+", - "workingSets" : "JVMCI,SPARC", - }, - "jdk.vm.ci.hotspot" : { "subDir" : "../jdk.internal.vm.ci/share/classes", "sourceDirs" : ["src"], @@ -205,18 +195,6 @@ "workingSets" : "JVMCI,HotSpot,AMD64", }, - "jdk.vm.ci.hotspot.sparc" : { - "subDir" : "../jdk.internal.vm.ci/share/classes", - "sourceDirs" : ["src"], - "dependencies" : [ - "jdk.vm.ci.sparc", - "jdk.vm.ci.hotspot", - ], - "checkstyle" : "jdk.vm.ci.services", - "javaCompliance" : "9+", - "workingSets" : "JVMCI,HotSpot,SPARC", - }, - "hotspot" : { "native" : True, "class" : "HotSpotProject", @@ -239,7 +217,6 @@ "jdk.vm.ci.common", "jdk.vm.ci.aarch64", "jdk.vm.ci.amd64", - "jdk.vm.ci.sparc", ], "distDependencies" : [ "JVMCI_SERVICES", @@ -251,7 +228,6 @@ "dependencies" : [ "jdk.vm.ci.hotspot.aarch64", "jdk.vm.ci.hotspot.amd64", - "jdk.vm.ci.hotspot.sparc", ], "distDependencies" : [ "JVMCI_SERVICES", diff --git a/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp b/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/abstractInterpreter_sparc.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 1997, 2017, 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. - * - */ - -#include "precompiled.hpp" -#include "interpreter/interpreter.hpp" -#include "oops/constMethod.hpp" -#include "oops/klass.inline.hpp" -#include "oops/method.hpp" -#include "runtime/arguments.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/synchronizer.hpp" -#include "utilities/align.hpp" -#include "utilities/macros.hpp" - - -int AbstractInterpreter::BasicType_as_index(BasicType type) { - int i = 0; - switch (type) { - case T_BOOLEAN: i = 0; break; - case T_CHAR : i = 1; break; - case T_BYTE : i = 2; break; - case T_SHORT : i = 3; break; - case T_INT : i = 4; break; - case T_LONG : i = 5; break; - case T_VOID : i = 6; break; - case T_FLOAT : i = 7; break; - case T_DOUBLE : i = 8; break; - case T_OBJECT : i = 9; break; - case T_ARRAY : i = 9; break; - default : ShouldNotReachHere(); - } - assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, "index out of bounds"); - return i; -} - -static int size_activation_helper(int callee_extra_locals, int max_stack, int monitor_size) { - - // Figure out the size of an interpreter frame (in words) given that we have a fully allocated - // expression stack, the callee will have callee_extra_locals (so we can account for - // frame extension) and monitor_size for monitors. Basically we need to calculate - // this exactly like generate_fixed_frame/generate_compute_interpreter_state. - // - // - // The big complicating thing here is that we must ensure that the stack stays properly - // aligned. This would be even uglier if monitor size wasn't modulo what the stack - // needs to be aligned for). We are given that the sp (fp) is already aligned by - // the caller so we must ensure that it is properly aligned for our callee. - // - const int rounded_vm_local_words = - align_up((int)frame::interpreter_frame_vm_local_words,WordsPerLong); - // callee_locals and max_stack are counts, not the size in frame. - const int locals_size = - align_up(callee_extra_locals * Interpreter::stackElementWords, WordsPerLong); - const int max_stack_words = max_stack * Interpreter::stackElementWords; - return (align_up((max_stack_words - + rounded_vm_local_words - + frame::memory_parameter_word_sp_offset), WordsPerLong) - // already rounded - + locals_size + monitor_size); -} - -// How much stack a method top interpreter activation needs in words. -int AbstractInterpreter::size_top_interpreter_activation(Method* method) { - - // See call_stub code - int call_stub_size = align_up(7 + frame::memory_parameter_word_sp_offset, - WordsPerLong); // 7 + register save area - - // Save space for one monitor to get into the interpreted method in case - // the method is synchronized - int monitor_size = method->is_synchronized() ? - 1*frame::interpreter_frame_monitor_size() : 0; - return size_activation_helper(method->max_locals(), method->max_stack(), - monitor_size) + call_stub_size; -} - -int AbstractInterpreter::size_activation(int max_stack, - int temps, - int extra_args, - int monitors, - int callee_params, - int callee_locals, - bool is_top_frame) { - // Note: This calculation must exactly parallel the frame setup - // in TemplateInterpreterGenerator::generate_fixed_frame. - - int monitor_size = monitors * frame::interpreter_frame_monitor_size(); - - assert(is_aligned(monitor_size, WordsPerLong), "must align"); - - // - // Note: if you look closely this appears to be doing something much different - // than generate_fixed_frame. What is happening is this. On sparc we have to do - // this dance with interpreter_sp_adjustment because the window save area would - // appear just below the bottom (tos) of the caller's java expression stack. Because - // the interpreter want to have the locals completely contiguous generate_fixed_frame - // will adjust the caller's sp for the "extra locals" (max_locals - parameter_size). - // Now in generate_fixed_frame the extension of the caller's sp happens in the callee. - // In this code the opposite occurs the caller adjusts it's own stack base on the callee. - // This is mostly ok but it does cause a problem when we get to the initial frame (the oldest) - // because the oldest frame would have adjust its callers frame and yet that frame - // already exists and isn't part of this array of frames we are unpacking. So at first - // glance this would seem to mess up that frame. However Deoptimization::fetch_unroll_info_helper() - // will after it calculates all of the frame's on_stack_size()'s will then figure out the - // amount to adjust the caller of the initial (oldest) frame and the calculation will all - // add up. It does seem like it simpler to account for the adjustment here (and remove the - // callee... parameters here). However this would mean that this routine would have to take - // the caller frame as input so we could adjust its sp (and set it's interpreter_sp_adjustment) - // and run the calling loop in the reverse order. This would also would appear to mean making - // this code aware of what the interactions are when that initial caller fram was an osr or - // other adapter frame. deoptimization is complicated enough and hard enough to debug that - // there is no sense in messing working code. - // - - int rounded_cls = align_up((callee_locals - callee_params), WordsPerLong); - assert(is_aligned(rounded_cls, WordsPerLong), "must align"); - - int raw_frame_size = size_activation_helper(rounded_cls, max_stack, monitor_size); - - return raw_frame_size; -} - -void AbstractInterpreter::layout_activation(Method* method, - int tempcount, - int popframe_extra_args, - int moncount, - int caller_actual_parameters, - int callee_param_count, - int callee_local_count, - frame* caller, - frame* interpreter_frame, - bool is_top_frame, - bool is_bottom_frame) { - // Set up the following variables: - // - Lmethod - // - Llocals - // - Lmonitors (to the indicated number of monitors) - // - Lesp (to the indicated number of temps) - // The frame caller on entry is a description of the caller of the - // frame we are about to layout. We are guaranteed that we will be - // able to fill in a new interpreter frame as its callee (i.e. the - // stack space is allocated and the amount was determined by an - // earlier call to the size_activation() method). On return caller - // while describe the interpreter frame we just layed out. - - // The skeleton frame must already look like an interpreter frame - // even if not fully filled out. - assert(interpreter_frame->is_interpreted_frame(), "Must be interpreted frame"); - - int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words,WordsPerLong); - int monitor_size = moncount * frame::interpreter_frame_monitor_size(); - assert(is_aligned(monitor_size, WordsPerLong), "must align"); - - intptr_t* fp = interpreter_frame->fp(); - - JavaThread* thread = JavaThread::current(); - RegisterMap map(thread, false); - // More verification that skeleton frame is properly walkable - assert(fp == caller->sp(), "fp must match"); - - intptr_t* montop = fp - rounded_vm_local_words; - - // preallocate monitors (cf. __ add_monitor_to_stack) - intptr_t* monitors = montop - monitor_size; - - // preallocate stack space - intptr_t* esp = monitors - 1 - - (tempcount * Interpreter::stackElementWords) - - popframe_extra_args; - - int local_words = method->max_locals() * Interpreter::stackElementWords; - NEEDS_CLEANUP; - intptr_t* locals; - if (caller->is_interpreted_frame()) { - // Can force the locals area to end up properly overlapping the top of the expression stack. - intptr_t* Lesp_ptr = caller->interpreter_frame_tos_address() - 1; - // Note that this computation means we replace size_of_parameters() values from the caller - // interpreter frame's expression stack with our argument locals - int parm_words = caller_actual_parameters * Interpreter::stackElementWords; - locals = Lesp_ptr + parm_words; - int delta = local_words - parm_words; - int computed_sp_adjustment = (delta > 0) ? align_up(delta, WordsPerLong) : 0; - *interpreter_frame->register_addr(I5_savedSP) = (intptr_t) (fp + computed_sp_adjustment) - STACK_BIAS; - if (!is_bottom_frame) { - // Llast_SP is set below for the current frame to SP (with the - // extra space for the callee's locals). Here we adjust - // Llast_SP for the caller's frame, removing the extra space - // for the current method's locals. - *caller->register_addr(Llast_SP) = *interpreter_frame->register_addr(I5_savedSP); - } else { - assert(*caller->register_addr(Llast_SP) >= *interpreter_frame->register_addr(I5_savedSP), "strange Llast_SP"); - } - } else { - assert(caller->is_compiled_frame() || caller->is_entry_frame(), "only possible cases"); - // Don't have Lesp available; lay out locals block in the caller - // adjacent to the register window save area. - // - // Compiled frames do not allocate a varargs area which is why this if - // statement is needed. - // - if (caller->is_compiled_frame()) { - locals = fp + frame::register_save_words + local_words - 1; - } else { - locals = fp + frame::memory_parameter_word_sp_offset + local_words - 1; - } - if (!caller->is_entry_frame()) { - // Caller wants his own SP back - int caller_frame_size = caller->cb()->frame_size(); - *interpreter_frame->register_addr(I5_savedSP) = (intptr_t)(caller->fp() - caller_frame_size) - STACK_BIAS; - } - } - if (TraceDeoptimization) { - if (caller->is_entry_frame()) { - // make sure I5_savedSP and the entry frames notion of saved SP - // agree. This assertion duplicate a check in entry frame code - // but catches the failure earlier. - assert(*caller->register_addr(Lscratch) == *interpreter_frame->register_addr(I5_savedSP), - "would change callers SP"); - } - if (caller->is_entry_frame()) { - tty->print("entry "); - } - if (caller->is_compiled_frame()) { - tty->print("compiled "); - if (caller->is_deoptimized_frame()) { - tty->print("(deopt) "); - } - } - if (caller->is_interpreted_frame()) { - tty->print("interpreted "); - } - tty->print_cr("caller fp=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, p2i(caller->fp()), p2i(caller->sp())); - tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(caller->sp()), p2i(caller->sp() + 16)); - tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(caller->fp()), p2i(caller->fp() + 16)); - tty->print_cr("interpreter fp=" INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(interpreter_frame->fp()), p2i(interpreter_frame->sp())); - tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(interpreter_frame->sp()), p2i(interpreter_frame->sp() + 16)); - tty->print_cr("save area = " INTPTR_FORMAT ", " INTPTR_FORMAT, p2i(interpreter_frame->fp()), p2i(interpreter_frame->fp() + 16)); - tty->print_cr("Llocals = " INTPTR_FORMAT, p2i(locals)); - tty->print_cr("Lesp = " INTPTR_FORMAT, p2i(esp)); - tty->print_cr("Lmonitors = " INTPTR_FORMAT, p2i(monitors)); - } - - if (method->max_locals() > 0) { - assert(locals < caller->sp() || locals >= (caller->sp() + 16), "locals in save area"); - assert(locals < caller->fp() || locals > (caller->fp() + 16), "locals in save area"); - assert(locals < interpreter_frame->sp() || locals > (interpreter_frame->sp() + 16), "locals in save area"); - assert(locals < interpreter_frame->fp() || locals >= (interpreter_frame->fp() + 16), "locals in save area"); - } - assert(*interpreter_frame->register_addr(I5_savedSP) & 1, "must be odd"); - - *interpreter_frame->register_addr(Lmethod) = (intptr_t) method; - *interpreter_frame->register_addr(Llocals) = (intptr_t) locals; - *interpreter_frame->register_addr(Lmonitors) = (intptr_t) monitors; - *interpreter_frame->register_addr(Lesp) = (intptr_t) esp; - // Llast_SP will be same as SP as there is no adapter space - *interpreter_frame->register_addr(Llast_SP) = (intptr_t) interpreter_frame->sp() - STACK_BIAS; - *interpreter_frame->register_addr(LcpoolCache) = (intptr_t) method->constants()->cache(); - // save the mirror in the interpreter frame - *interpreter_frame->interpreter_frame_mirror_addr() = method->method_holder()->java_mirror(); - -#ifdef ASSERT - BasicObjectLock* mp = (BasicObjectLock*)monitors; - - assert(interpreter_frame->interpreter_frame_method() == method, "method matches"); - assert(interpreter_frame->interpreter_frame_local_at(9) == (intptr_t *)((intptr_t)locals - (9 * Interpreter::stackElementSize)), "locals match"); - assert(interpreter_frame->interpreter_frame_monitor_end() == mp, "monitor_end matches"); - assert(((intptr_t *)interpreter_frame->interpreter_frame_monitor_begin()) == ((intptr_t *)mp)+monitor_size, "monitor_begin matches"); - assert(interpreter_frame->interpreter_frame_tos_address()-1 == esp, "esp matches"); - - // check bounds - intptr_t* lo = interpreter_frame->sp() + (frame::memory_parameter_word_sp_offset - 1); - intptr_t* hi = interpreter_frame->fp() - rounded_vm_local_words; - assert(lo < monitors && montop <= hi, "monitors in bounds"); - assert(lo <= esp && esp < monitors, "esp in bounds"); -#endif // ASSERT -} diff --git a/src/hotspot/cpu/sparc/args.cc b/src/hotspot/cpu/sparc/args.cc deleted file mode 100644 --- a/src/hotspot/cpu/sparc/args.cc +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (c) 2002, 2006, 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. - * - */ - -#include -#include - -static const int R_O0_num = 1000; -static const int R_I0_num = 2000; -static const int R_F0_num = 3000; -static const int R_F1_num = R_F0_num + 1; -static const int R_F2_num = R_F0_num + 2; -static const int STACK_num= 4000; - -static bool LP64 = false; -static bool LONGS_IN_ONE_ENTRY = false; - -static const int Op_RegI = 'I'; -static const int Op_RegP = 'P'; -static const int Op_RegF = 'F'; -static const int Op_RegD = 'D'; -static const int Op_RegL = 'L'; -static const int SPARC_ARGS_IN_REGS_NUM=6; - -static void print_reg( int reg ) { - if( reg == 0 ) - printf("__"); // halve's - else if( reg >= STACK_num && reg < STACK_num+100 ) - printf("S%d_",reg - STACK_num); - else if( reg >= R_F0_num && reg < R_F0_num+100 ) - printf("F%d_",reg - R_F0_num); - else if( reg >= R_O0_num && reg < R_O0_num+100 ) { - if( LONGS_IN_ONE_ENTRY ) { - reg -= R_O0_num; - printf("O%d",reg>>1); - printf(reg&1 ? "H" : "L"); - } else - printf("O%d_",reg - R_O0_num); - } else - printf("Wretched: %d\n", reg); -} - -static void print_convention( int *sig, const char *s, int length ) { - // Print it out - for( int i = 0; i < length; i++) { - if( sig[i] == 0 ) continue; // do not print 'halves' - print_reg( sig[i] & 0xFFFF ); - int reg = sig[i] >> 16; - if( reg ) { - printf(":"); - print_reg( reg ); - } else { - printf(" "); - } - printf(" "); - } - printf("\n"); -} - -static int INT_SCALE( int x ) { - return LONGS_IN_ONE_ENTRY ? (x<<1) : x; -} - -static void java_convention( int *sig, const char *s, int length ) { - if( LP64 && !LONGS_IN_ONE_ENTRY ) { - printf("LP64 and 2-reg longs not supported\n"); - return; - } - for( int i = 0; i < length; i++ ) - sig[i] = s[i]; // Reset sig array - bool is_outgoing = true; - - int int_base = (is_outgoing ? R_O0_num : R_I0_num); - - // Convention is to pack the first 6 int/oop args into the first 6 - // registers (I0-I5), extras spill to the stack. Then pack the first - // 32 float args into F0-F31, extras spill to the stack. Then pad - // all register sets to align. Then put longs and doubles into the - // same registers as they fit, else spill to the stack. - int int_reg_max = SPARC_ARGS_IN_REGS_NUM; - int flt_reg_max = 32; - - // Count int/oop and float args. See how many stack slots we'll need - // and where the longs & doubles will go. - int int_reg_cnt = 0; - int flt_reg_cnt = 0; - int stk_reg_pairs = 0; - for( int i = 0; i < length; i++) { - switch( sig[i] ) { - case Op_RegL: // Longs-in-1-reg compete with int args - if( LONGS_IN_ONE_ENTRY ) { - if( int_reg_cnt < int_reg_max ) int_reg_cnt++; - } - break; - case Op_RegP: - if( int_reg_cnt < int_reg_max ) int_reg_cnt++; - else if( !LP64 ) stk_reg_pairs++; - break; - case Op_RegI: - if( int_reg_cnt < int_reg_max ) int_reg_cnt++; - else stk_reg_pairs++; - break; - case Op_RegF: - if( flt_reg_cnt < flt_reg_max ) flt_reg_cnt++; - else stk_reg_pairs++; - break; - } - } - - // This is where the longs/doubles start on the stack. - stk_reg_pairs = (stk_reg_pairs+1) & ~1; // Round - - int int_reg_pairs = (int_reg_cnt+1) & ~1; // 32-bit 2-reg longs only - int flt_reg_pairs = (flt_reg_cnt+1) & ~1; - - int stk_reg = 0; - int int_reg = 0; - int flt_reg = 0; - - // Now do the signature layout - for( int i = 0; i < length; i++) { - int tmp = sig[i]; - if( tmp == Op_RegP ) - tmp = LP64 ? Op_RegL : Op_RegI; // Treat ptrs and ints or long accordingly - switch( tmp ) { - case Op_RegI: -// case Op_RegP: - if( int_reg < int_reg_max) tmp = INT_SCALE(int_reg++) + int_base; - else tmp = STACK_num + stk_reg++; - sig[i] = tmp; - break; - - case Op_RegL: - if( sig[i] != Op_RegP && sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; } -// case Op_RegP: - if( LONGS_IN_ONE_ENTRY ) { - if( int_reg < int_reg_max ) { - tmp = INT_SCALE(int_reg++) + int_base; - } else { - tmp = STACK_num + stk_reg_pairs; - stk_reg_pairs += 2; - } - } else { - if( int_reg_pairs < int_reg_max ) { - tmp = int_reg_pairs + int_base; - int_reg_pairs += 2; - } else { - tmp = STACK_num + stk_reg_pairs; - stk_reg_pairs += 2; - } - } - sig[i] = tmp | (tmp+1)<<16; // Smear to pair - break; - - case Op_RegF: - sig[i] = (flt_reg < flt_reg_max) ? (R_F0_num + flt_reg++) : STACK_num + stk_reg++; - break; - case Op_RegD: - if( sig[i+1] != 'h' ) { printf("expecting (h)alf, found %c\n", sig[i+1]); return; } - if( flt_reg_pairs < flt_reg_max ) { - tmp = R_F0_num + flt_reg_pairs; - flt_reg_pairs += 2; - } else { - tmp = STACK_num + stk_reg_pairs; - stk_reg_pairs += 2; - } - sig[i] = tmp | (tmp+1)<<16; // Smear to pair - break; - case 'h': sig[i] = 0; break; - default: - printf("Bad character: %c\n", sig[i] ); - return; - } - } - - printf("java "); - printf(LP64 ? "LP64 " : "LP32 "); - printf(LONGS_IN_ONE_ENTRY ? "long1: " : "long2: "); - print_convention(sig,s,length); -} - -static int int_stk_helper( int i ) { - if( i < 6 ) return R_O0_num + (LONGS_IN_ONE_ENTRY ? i<<1 : i); - else return STACK_num + (LP64 ? i<<1 : i); -} - -static void native_convention( int *sig, const char *s, int length ) { - if( LP64 && !LONGS_IN_ONE_ENTRY ) { - printf("LP64 and 2-reg longs not supported\n"); - return; - } - for( int i = 0; i < length; i++ ) - sig[i] = s[i]; // Reset sig array - - // The native convention is V8 if !LP64, which means the V8 convention is - // used both with and without LONGS_IN_ONE_ENTRY, an unfortunate split. The - // same actual machine registers are used, but they are named differently in - // the LONGS_IN_ONE_ENTRY mode. The LP64 convention is the V9 convention - // which is slightly more sane. - - if( LP64 ) { - // V9 convention: All things "as-if" on double-wide stack slots. - // Hoist any int/ptr/long's in the first 6 to int regs. - // Hoist any flt/dbl's in the first 16 dbl regs. - int j = 0; // Count of actual args, not HALVES - for( int i=0; istart(); - address addrN = csect->end(); - uint32_t prev = 0; - - assert((addrN - addr0) % BytesPerInstWord == 0, "must be"); - - for (address pc = addr0; pc != addrN; pc += BytesPerInstWord) { - uint32_t insn = *reinterpret_cast(pc); - - // 1. General case: No CTI immediately after other CTI - assert(!(is_cti(prev) && is_cti(insn)), "CTI-CTI not allowed."); - - // 2. Special case: No CTI immediately after/before RDPC - assert(!(is_cti(prev) && is_rdpc(insn)), "CTI-RDPC not allowed."); - assert(!(is_rdpc(prev) && is_cti(insn)), "RDPC-CTI not allowed."); - - prev = insn; - } -} -#endif diff --git a/src/hotspot/cpu/sparc/assembler_sparc.hpp b/src/hotspot/cpu/sparc/assembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/assembler_sparc.hpp +++ /dev/null @@ -1,1339 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_ASSEMBLER_SPARC_HPP -#define CPU_SPARC_ASSEMBLER_SPARC_HPP - -#include "asm/register.hpp" - -// The SPARC Assembler: Pure assembler doing NO optimizations on the instruction -// level; i.e., what you write is what you get. The Assembler is generating code -// into a CodeBuffer. - -class Assembler : public AbstractAssembler { - friend class AbstractAssembler; - friend class AddressLiteral; - - // code patchers need various routines like inv_wdisp() - friend class NativeInstruction; - friend class NativeGeneralJump; - friend class Relocation; - friend class Label; - - public: - // op carries format info; see page 62 & 267 - - enum ops { - call_op = 1, // fmt 1 - branch_op = 0, // also sethi (fmt2) - arith_op = 2, // fmt 3, arith & misc - ldst_op = 3 // fmt 3, load/store - }; - - enum op2s { - bpr_op2 = 3, - fb_op2 = 6, - fbp_op2 = 5, - br_op2 = 2, - bp_op2 = 1, - sethi_op2 = 4 - }; - - enum op3s { - // selected op3s - add_op3 = 0x00, - and_op3 = 0x01, - or_op3 = 0x02, - xor_op3 = 0x03, - sub_op3 = 0x04, - andn_op3 = 0x05, - orn_op3 = 0x06, - xnor_op3 = 0x07, - addc_op3 = 0x08, - mulx_op3 = 0x09, - umul_op3 = 0x0a, - smul_op3 = 0x0b, - subc_op3 = 0x0c, - udivx_op3 = 0x0d, - udiv_op3 = 0x0e, - sdiv_op3 = 0x0f, - - addcc_op3 = 0x10, - andcc_op3 = 0x11, - orcc_op3 = 0x12, - xorcc_op3 = 0x13, - subcc_op3 = 0x14, - andncc_op3 = 0x15, - orncc_op3 = 0x16, - xnorcc_op3 = 0x17, - addccc_op3 = 0x18, - aes4_op3 = 0x19, - umulcc_op3 = 0x1a, - smulcc_op3 = 0x1b, - subccc_op3 = 0x1c, - udivcc_op3 = 0x1e, - sdivcc_op3 = 0x1f, - - taddcc_op3 = 0x20, - tsubcc_op3 = 0x21, - taddcctv_op3 = 0x22, - tsubcctv_op3 = 0x23, - mulscc_op3 = 0x24, - sll_op3 = 0x25, - sllx_op3 = 0x25, - srl_op3 = 0x26, - srlx_op3 = 0x26, - sra_op3 = 0x27, - srax_op3 = 0x27, - rdreg_op3 = 0x28, - membar_op3 = 0x28, - - flushw_op3 = 0x2b, - movcc_op3 = 0x2c, - sdivx_op3 = 0x2d, - popc_op3 = 0x2e, - movr_op3 = 0x2f, - - sir_op3 = 0x30, - wrreg_op3 = 0x30, - saved_op3 = 0x31, - - fpop1_op3 = 0x34, - fpop2_op3 = 0x35, - impdep1_op3 = 0x36, - addx_op3 = 0x36, - aes3_op3 = 0x36, - sha_op3 = 0x36, - bmask_op3 = 0x36, - bshuffle_op3 = 0x36, - alignaddr_op3 = 0x36, - faligndata_op3 = 0x36, - flog3_op3 = 0x36, - edge_op3 = 0x36, - fzero_op3 = 0x36, - fsrc_op3 = 0x36, - fnot_op3 = 0x36, - mpmul_op3 = 0x36, - umulx_op3 = 0x36, - xmulx_op3 = 0x36, - crc32c_op3 = 0x36, - impdep2_op3 = 0x37, - stpartialf_op3 = 0x37, - jmpl_op3 = 0x38, - rett_op3 = 0x39, - trap_op3 = 0x3a, - flush_op3 = 0x3b, - save_op3 = 0x3c, - restore_op3 = 0x3d, - done_op3 = 0x3e, - retry_op3 = 0x3e, - - lduw_op3 = 0x00, - ldub_op3 = 0x01, - lduh_op3 = 0x02, - ldd_op3 = 0x03, - stw_op3 = 0x04, - stb_op3 = 0x05, - sth_op3 = 0x06, - std_op3 = 0x07, - ldsw_op3 = 0x08, - ldsb_op3 = 0x09, - ldsh_op3 = 0x0a, - ldx_op3 = 0x0b, - - stx_op3 = 0x0e, - swap_op3 = 0x0f, - - stwa_op3 = 0x14, - stxa_op3 = 0x1e, - - ldf_op3 = 0x20, - ldfsr_op3 = 0x21, - ldqf_op3 = 0x22, - lddf_op3 = 0x23, - stf_op3 = 0x24, - stfsr_op3 = 0x25, - stqf_op3 = 0x26, - stdf_op3 = 0x27, - - prefetch_op3 = 0x2d, - - casa_op3 = 0x3c, - casxa_op3 = 0x3e, - - mftoi_op3 = 0x36, - - alt_bit_op3 = 0x10, - cc_bit_op3 = 0x10 - }; - - enum opfs { - // selected opfs - edge8n_opf = 0x01, - - fmovs_opf = 0x01, - fmovd_opf = 0x02, - - fnegs_opf = 0x05, - fnegd_opf = 0x06, - - addxc_opf = 0x11, - addxccc_opf = 0x13, - umulxhi_opf = 0x16, - alignaddr_opf = 0x18, - bmask_opf = 0x19, - - fadds_opf = 0x41, - faddd_opf = 0x42, - fsubs_opf = 0x45, - fsubd_opf = 0x46, - - faligndata_opf = 0x48, - - fmuls_opf = 0x49, - fmuld_opf = 0x4a, - bshuffle_opf = 0x4c, - fdivs_opf = 0x4d, - fdivd_opf = 0x4e, - - fcmps_opf = 0x51, - fcmpd_opf = 0x52, - - fstox_opf = 0x81, - fdtox_opf = 0x82, - fxtos_opf = 0x84, - fxtod_opf = 0x88, - fitos_opf = 0xc4, - fdtos_opf = 0xc6, - fitod_opf = 0xc8, - fstod_opf = 0xc9, - fstoi_opf = 0xd1, - fdtoi_opf = 0xd2, - - mdtox_opf = 0x110, - mstouw_opf = 0x111, - mstosw_opf = 0x113, - xmulx_opf = 0x115, - xmulxhi_opf = 0x116, - mxtod_opf = 0x118, - mwtos_opf = 0x119, - - aes_kexpand0_opf = 0x130, - aes_kexpand2_opf = 0x131, - - sha1_opf = 0x141, - sha256_opf = 0x142, - sha512_opf = 0x143, - - crc32c_opf = 0x147, - mpmul_opf = 0x148 - }; - - enum op5s { - aes_eround01_op5 = 0x00, - aes_eround23_op5 = 0x01, - aes_dround01_op5 = 0x02, - aes_dround23_op5 = 0x03, - aes_eround01_l_op5 = 0x04, - aes_eround23_l_op5 = 0x05, - aes_dround01_l_op5 = 0x06, - aes_dround23_l_op5 = 0x07, - aes_kexpand1_op5 = 0x08 - }; - - enum RCondition { rc_z = 1, rc_lez = 2, rc_lz = 3, rc_nz = 5, rc_gz = 6, rc_gez = 7, rc_last = rc_gez }; - - enum Condition { - // for FBfcc & FBPfcc instruction - f_never = 0, - f_notEqual = 1, - f_notZero = 1, - f_lessOrGreater = 2, - f_unorderedOrLess = 3, - f_less = 4, - f_unorderedOrGreater = 5, - f_greater = 6, - f_unordered = 7, - f_always = 8, - f_equal = 9, - f_zero = 9, - f_unorderedOrEqual = 10, - f_greaterOrEqual = 11, - f_unorderedOrGreaterOrEqual = 12, - f_lessOrEqual = 13, - f_unorderedOrLessOrEqual = 14, - f_ordered = 15, - - // for integers - - never = 0, - equal = 1, - zero = 1, - lessEqual = 2, - less = 3, - lessEqualUnsigned = 4, - lessUnsigned = 5, - carrySet = 5, - negative = 6, - overflowSet = 7, - always = 8, - notEqual = 9, - notZero = 9, - greater = 10, - greaterEqual = 11, - greaterUnsigned = 12, - greaterEqualUnsigned = 13, - carryClear = 13, - positive = 14, - overflowClear = 15 - }; - - enum CC { - // ptr_cc is the correct condition code for a pointer or intptr_t: - icc = 0, xcc = 2, ptr_cc = xcc, - fcc0 = 0, fcc1 = 1, fcc2 = 2, fcc3 = 3 - }; - - enum PrefetchFcn { - severalReads = 0, oneRead = 1, severalWritesAndPossiblyReads = 2, oneWrite = 3, page = 4 - }; - - public: - // Helper functions for groups of instructions - - enum Predict { pt = 1, pn = 0 }; // pt = predict taken - - enum Membar_mask_bits { // page 184, v9 - StoreStore = 1 << 3, - LoadStore = 1 << 2, - StoreLoad = 1 << 1, - LoadLoad = 1 << 0, - - Sync = 1 << 6, - MemIssue = 1 << 5, - Lookaside = 1 << 4 - }; - - //---< calculate length of instruction >--- - // With SPARC being a RISC architecture, this always is BytesPerInstWord - // instruction must start at passed address - static unsigned int instr_len(unsigned char *instr) { return BytesPerInstWord; } - - //---< longest instructions >--- - static unsigned int instr_maxlen() { return BytesPerInstWord; } - - static bool is_in_wdisp_range(address a, address b, int nbits) { - intptr_t d = intptr_t(b) - intptr_t(a); - return is_simm(d, nbits + 2); - } - - address target_distance(Label &L) { - // Assembler::target(L) should be called only when - // a branch instruction is emitted since non-bound - // labels record current pc() as a branch address. - if (L.is_bound()) return target(L); - // Return current address for non-bound labels. - return pc(); - } - - // test if label is in simm16 range in words (wdisp16). - bool is_in_wdisp16_range(Label &L) { - return is_in_wdisp_range(target_distance(L), pc(), 16); - } - // test if the distance between two addresses fits in simm30 range in words - static bool is_in_wdisp30_range(address a, address b) { - return is_in_wdisp_range(a, b, 30); - } - - enum ASIs { // page 72, v9 - ASI_PRIMARY = 0x80, - ASI_PRIMARY_NOFAULT = 0x82, - ASI_PRIMARY_LITTLE = 0x88, - // 8x8-bit partial store - ASI_PST8_PRIMARY = 0xC0, - // Block initializing store - ASI_ST_BLKINIT_PRIMARY = 0xE2, - // Most-Recently-Used (MRU) BIS variant - ASI_ST_BLKINIT_MRU_PRIMARY = 0xF2 - // add more from book as needed - }; - - protected: - // helpers - - // x is supposed to fit in a field "nbits" wide - // and be sign-extended. Check the range. - - static void assert_signed_range(intptr_t x, int nbits) { - assert(nbits == 32 || (-(1 << nbits-1) <= x && x < (1 << nbits-1)), - "value out of range: x=" INTPTR_FORMAT ", nbits=%d", x, nbits); - } - - static void assert_signed_word_disp_range(intptr_t x, int nbits) { - assert((x & 3) == 0, "not word aligned"); - assert_signed_range(x, nbits + 2); - } - - static void assert_unsigned_range(int x, int nbits) { - assert(juint(x) < juint(1 << nbits), "unsigned constant out of range"); - } - - // fields: note bits numbered from LSB = 0, fields known by inclusive bit range - - static int fmask(juint hi_bit, juint lo_bit) { - assert(hi_bit >= lo_bit && 0 <= lo_bit && hi_bit < 32, "bad bits"); - return (1 << (hi_bit-lo_bit + 1)) - 1; - } - - // inverse of u_field - - static int inv_u_field(int x, int hi_bit, int lo_bit) { - juint r = juint(x) >> lo_bit; - r &= fmask(hi_bit, lo_bit); - return int(r); - } - - // signed version: extract from field and sign-extend - - static int inv_s_field(int x, int hi_bit, int lo_bit) { - int sign_shift = 31 - hi_bit; - return inv_u_field(((x << sign_shift) >> sign_shift), hi_bit, lo_bit); - } - - // given a field that ranges from hi_bit to lo_bit (inclusive, - // LSB = 0), and an unsigned value for the field, - // shift it into the field - -#ifdef ASSERT - static int u_field(int x, int hi_bit, int lo_bit) { - assert((x & ~fmask(hi_bit, lo_bit)) == 0, - "value out of range"); - int r = x << lo_bit; - assert(inv_u_field(r, hi_bit, lo_bit) == x, "just checking"); - return r; - } -#else - // make sure this is inlined as it will reduce code size significantly - #define u_field(x, hi_bit, lo_bit) ((x) << (lo_bit)) -#endif - - static int inv_op(int x) { return inv_u_field(x, 31, 30); } - static int inv_op2(int x) { return inv_u_field(x, 24, 22); } - static int inv_op3(int x) { return inv_u_field(x, 24, 19); } - static int inv_cond(int x) { return inv_u_field(x, 28, 25); } - - static bool inv_immed(int x) { return (x & Assembler::immed(true)) != 0; } - - static Register inv_rd(int x) { return as_Register(inv_u_field(x, 29, 25)); } - static Register inv_rs1(int x) { return as_Register(inv_u_field(x, 18, 14)); } - static Register inv_rs2(int x) { return as_Register(inv_u_field(x, 4, 0)); } - - static int op(int x) { return u_field(x, 31, 30); } - static int rd(Register r) { return u_field(r->encoding(), 29, 25); } - static int fcn(int x) { return u_field(x, 29, 25); } - static int op3(int x) { return u_field(x, 24, 19); } - static int rs1(Register r) { return u_field(r->encoding(), 18, 14); } - static int rs2(Register r) { return u_field(r->encoding(), 4, 0); } - static int annul(bool a) { return u_field(a ? 1 : 0, 29, 29); } - static int cond(int x) { return u_field(x, 28, 25); } - static int cond_mov(int x) { return u_field(x, 17, 14); } - static int rcond(RCondition x) { return u_field(x, 12, 10); } - static int op2(int x) { return u_field(x, 24, 22); } - static int predict(bool p) { return u_field(p ? 1 : 0, 19, 19); } - static int branchcc(CC fcca) { return u_field(fcca, 21, 20); } - static int cmpcc(CC fcca) { return u_field(fcca, 26, 25); } - static int imm_asi(int x) { return u_field(x, 12, 5); } - static int immed(bool i) { return u_field(i ? 1 : 0, 13, 13); } - static int opf_low6(int w) { return u_field(w, 10, 5); } - static int opf_low5(int w) { return u_field(w, 9, 5); } - static int op5(int x) { return u_field(x, 8, 5); } - static int trapcc(CC cc) { return u_field(cc, 12, 11); } - static int sx(int i) { return u_field(i, 12, 12); } // shift x=1 means 64-bit - static int opf(int x) { return u_field(x, 13, 5); } - - static bool is_cbcond(int x) { - return (VM_Version::has_cbcond() && (inv_cond(x) > rc_last) && - inv_op(x) == branch_op && inv_op2(x) == bpr_op2); - } - static bool is_cxb(int x) { - assert(is_cbcond(x), "wrong instruction"); - return (x & (1 << 21)) != 0; - } - static bool is_branch(int x) { - if (inv_op(x) != Assembler::branch_op) return false; - - bool is_bpr = inv_op2(x) == Assembler::bpr_op2; - bool is_bp = inv_op2(x) == Assembler::bp_op2; - bool is_br = inv_op2(x) == Assembler::br_op2; - bool is_fp = inv_op2(x) == Assembler::fb_op2; - bool is_fbp = inv_op2(x) == Assembler::fbp_op2; - - return is_bpr || is_bp || is_br || is_fp || is_fbp; - } - static bool is_call(int x) { - return inv_op(x) == Assembler::call_op; - } - static bool is_jump(int x) { - if (inv_op(x) != Assembler::arith_op) return false; - - bool is_jmpl = inv_op3(x) == Assembler::jmpl_op3; - bool is_rett = inv_op3(x) == Assembler::rett_op3; - - return is_jmpl || is_rett; - } - static bool is_rdpc(int x) { - return (inv_op(x) == Assembler::arith_op && inv_op3(x) == Assembler::rdreg_op3 && - inv_u_field(x, 18, 14) == 5); - } - static bool is_cti(int x) { - return is_branch(x) || is_call(x) || is_jump(x); // Ignoring done/retry - } - - static int cond_cbcond(int x) { return u_field((((x & 8) << 1) + 8 + (x & 7)), 29, 25); } - static int inv_cond_cbcond(int x) { - assert(is_cbcond(x), "wrong instruction"); - return inv_u_field(x, 27, 25) | (inv_u_field(x, 29, 29) << 3); - } - - static int opf_cc(CC c, bool useFloat) { return u_field((useFloat ? 0 : 4) + c, 13, 11); } - static int mov_cc(CC c, bool useFloat) { return u_field(useFloat ? 0 : 1, 18, 18) | u_field(c, 12, 11); } - - static int fd(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 29, 25); }; - static int fs1(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 18, 14); }; - static int fs2(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 4, 0); }; - static int fs3(FloatRegister r, FloatRegisterImpl::Width fwa) { return u_field(r->encoding(fwa), 13, 9); }; - - // some float instructions use this encoding on the op3 field - static int alt_op3(int op, FloatRegisterImpl::Width w) { - int r; - switch(w) { - case FloatRegisterImpl::S: r = op + 0; break; - case FloatRegisterImpl::D: r = op + 3; break; - case FloatRegisterImpl::Q: r = op + 2; break; - default: ShouldNotReachHere(); break; - } - return op3(r); - } - - // compute inverse of simm - static int inv_simm(int x, int nbits) { - return (int)(x << (32 - nbits)) >> (32 - nbits); - } - - static int inv_simm13(int x) { return inv_simm(x, 13); } - - // signed immediate, in low bits, nbits long - static int simm(int x, int nbits) { - assert_signed_range(x, nbits); - return x & ((1 << nbits) - 1); - } - - // unsigned immediate, in low bits, at most nbits long. - static int uimm(int x, int nbits) { - assert_unsigned_range(x, nbits); - return x & ((1 << nbits) - 1); - } - - // compute inverse of wdisp16 - static intptr_t inv_wdisp16(int x, intptr_t pos) { - int lo = x & ((1 << 14) - 1); - int hi = (x >> 20) & 3; - if (hi >= 2) hi |= ~1; - return (((hi << 14) | lo) << 2) + pos; - } - - // word offset, 14 bits at LSend, 2 bits at B21, B20 - static int wdisp16(intptr_t x, intptr_t off) { - intptr_t xx = x - off; - assert_signed_word_disp_range(xx, 16); - int r = (xx >> 2) & ((1 << 14) - 1) | (((xx >> (2+14)) & 3) << 20); - assert(inv_wdisp16(r, off) == x, "inverse is not inverse"); - return r; - } - - // compute inverse of wdisp10 - static intptr_t inv_wdisp10(int x, intptr_t pos) { - assert(is_cbcond(x), "wrong instruction"); - int lo = inv_u_field(x, 12, 5); - int hi = (x >> 19) & 3; - if (hi >= 2) hi |= ~1; - return (((hi << 8) | lo) << 2) + pos; - } - - // word offset for cbcond, 8 bits at [B12,B5], 2 bits at [B20,B19] - static int wdisp10(intptr_t x, intptr_t off) { - assert(VM_Version::has_cbcond(), "This CPU does not have CBCOND instruction"); - intptr_t xx = x - off; - assert_signed_word_disp_range(xx, 10); - int r = (((xx >> 2) & ((1 << 8) - 1)) << 5) | (((xx >> (2+8)) & 3) << 19); - // Have to fake cbcond instruction to pass assert in inv_wdisp10() - assert(inv_wdisp10((r | op(branch_op) | cond_cbcond(rc_last+1) | op2(bpr_op2)), off) == x, "inverse is not inverse"); - return r; - } - - // word displacement in low-order nbits bits - - static intptr_t inv_wdisp(int x, intptr_t pos, int nbits) { - int pre_sign_extend = x & ((1 << nbits) - 1); - int r = (pre_sign_extend >= (1 << (nbits - 1)) ? - pre_sign_extend | ~((1 << nbits) - 1) : pre_sign_extend); - return (r << 2) + pos; - } - - static int wdisp(intptr_t x, intptr_t off, int nbits) { - intptr_t xx = x - off; - assert_signed_word_disp_range(xx, nbits); - int r = (xx >> 2) & ((1 << nbits) - 1); - assert(inv_wdisp(r, off, nbits) == x, "inverse not inverse"); - return r; - } - - - // Extract the top 32 bits in a 64 bit word - static int32_t hi32(int64_t x) { - int32_t r = int32_t((uint64_t)x >> 32); - return r; - } - - // given a sethi instruction, extract the constant, left-justified - static int inv_hi22(int x) { - return x << 10; - } - - // create an imm22 field, given a 32-bit left-justified constant - static int hi22(int x) { - int r = int(juint(x) >> 10); - assert((r & ~((1 << 22) - 1)) == 0, "just checkin'"); - return r; - } - - // create a low10 __value__ (not a field) for a given a 32-bit constant - static int low10(int x) { - return x & ((1 << 10) - 1); - } - - // create a low12 __value__ (not a field) for a given a 32-bit constant - static int low12(int x) { - return x & ((1 << 12) - 1); - } - - // AES crypto instructions supported only on certain processors - static void aes_only() { assert(VM_Version::has_aes(), "This instruction only works on SPARC with AES instructions support"); } - - // SHA crypto instructions supported only on certain processors - static void sha1_only() { assert(VM_Version::has_sha1(), "This instruction only works on SPARC with SHA1"); } - static void sha256_only() { assert(VM_Version::has_sha256(), "This instruction only works on SPARC with SHA256"); } - static void sha512_only() { assert(VM_Version::has_sha512(), "This instruction only works on SPARC with SHA512"); } - - // CRC32C instruction supported only on certain processors - static void crc32c_only() { assert(VM_Version::has_crc32c(), "This instruction only works on SPARC with CRC32C"); } - - // FMAf instructions supported only on certain processors - static void fmaf_only() { assert(VM_Version::has_fmaf(), "This instruction only works on SPARC with FMAf"); } - - // MPMUL instruction supported only on certain processors - static void mpmul_only() { assert(VM_Version::has_mpmul(), "This instruction only works on SPARC with MPMUL"); } - - // instruction only in VIS1 - static void vis1_only() { assert(VM_Version::has_vis1(), "This instruction only works on SPARC with VIS1"); } - - // instruction only in VIS2 - static void vis2_only() { assert(VM_Version::has_vis2(), "This instruction only works on SPARC with VIS2"); } - - // instruction only in VIS3 - static void vis3_only() { assert(VM_Version::has_vis3(), "This instruction only works on SPARC with VIS3"); } - - // instruction deprecated in v9 - static void v9_dep() { } // do nothing for now - - protected: -#ifdef ASSERT -#define VALIDATE_PIPELINE -#endif - -#ifdef VALIDATE_PIPELINE - // A simple delay-slot scheme: - // In order to check the programmer, the assembler keeps track of delay-slots. - // It forbids CTIs in delay-slots (conservative, but should be OK). Also, when - // emitting an instruction into a delay-slot, you must do so using delayed(), - // e.g. asm->delayed()->add(...), in order to check that you do not omit the - // delay-slot instruction. To implement this, we use a simple FSA. - enum { NoDelay, AtDelay, FillDelay } _delay_state; - - // A simple hazard scheme: - // In order to avoid pipeline stalls, due to single cycle pipeline hazards, we - // adopt a simplistic state tracking mechanism that will enforce an additional - // 'nop' instruction to be inserted prior to emitting an instruction that can - // expose a given hazard (currently, PC-related hazards only). - enum { NoHazard, PcHazard } _hazard_state; -#endif - - public: - // Tell the assembler that the next instruction must NOT be in delay-slot. - // Use at start of multi-instruction macros. - void assert_not_delayed() { - // This is a separate entry to avoid the creation of string constants in - // non-asserted code, with some compilers this pollutes the object code. -#ifdef VALIDATE_PIPELINE - assert_no_delay("Next instruction should not be in a delay-slot."); -#endif - } - - protected: - void assert_no_delay(const char* msg) { -#ifdef VALIDATE_PIPELINE - assert(_delay_state == NoDelay, msg); -#endif - } - - void assert_no_hazard() { -#ifdef VALIDATE_PIPELINE - assert(_hazard_state == NoHazard, "Unsolicited pipeline hazard."); -#endif - } - - private: - inline int32_t prev_insn() { - assert(offset() > 0, "Interface violation."); - int32_t* addr = (int32_t*)pc() - 1; - return *addr; - } - -#ifdef VALIDATE_PIPELINE - void validate_no_pipeline_hazards(); -#endif - - protected: - // Avoid possible pipeline stall by inserting an additional 'nop' instruction, - // if the previous instruction is a 'cbcond' or a 'rdpc'. - inline void avoid_pipeline_stall(); - - // A call to cti() is made before emitting a control-transfer instruction (CTI) - // in order to assert a CTI is not emitted right after a 'cbcond', nor in the - // delay-slot of another CTI. Only effective when assertions are enabled. - void cti() { - // A 'cbcond' or 'rdpc' instruction immediately followed by a CTI introduces - // a pipeline stall, which we make sure to prohibit. - assert_no_cbcond_before(); - assert_no_rdpc_before(); -#ifdef VALIDATE_PIPELINE - assert_no_hazard(); - assert_no_delay("CTI in delay-slot."); -#endif - } - - // Called when emitting CTI with a delay-slot, AFTER emitting. - inline void induce_delay_slot() { -#ifdef VALIDATE_PIPELINE - assert_no_delay("Already in delay-slot."); - _delay_state = AtDelay; -#endif - } - - inline void induce_pc_hazard() { -#ifdef VALIDATE_PIPELINE - assert_no_hazard(); - _hazard_state = PcHazard; -#endif - } - - bool is_cbcond_before() { return offset() > 0 ? is_cbcond(prev_insn()) : false; } - - bool is_rdpc_before() { return offset() > 0 ? is_rdpc(prev_insn()) : false; } - - void assert_no_cbcond_before() { - assert(offset() == 0 || !is_cbcond_before(), "CBCOND should not be followed by CTI."); - } - - void assert_no_rdpc_before() { - assert(offset() == 0 || !is_rdpc_before(), "RDPC should not be followed by CTI."); - } - - public: - - bool use_cbcond(Label &L) { - if (!UseCBCond || is_cbcond_before()) return false; - intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc()); - assert((x & 3) == 0, "not word aligned"); - return is_simm12(x); - } - - // Tells assembler you know that next instruction is delayed - Assembler* delayed() { -#ifdef VALIDATE_PIPELINE - assert(_delay_state == AtDelay, "Delayed instruction not in delay-slot."); - _delay_state = FillDelay; -#endif - return this; - } - - void flush() { -#ifdef VALIDATE_PIPELINE - assert(_delay_state == NoDelay, "Ending code with a delay-slot."); -#ifdef COMPILER2 - validate_no_pipeline_hazards(); -#endif -#endif - AbstractAssembler::flush(); - } - - inline void emit_int32(int32_t); // shadows AbstractAssembler::emit_int32 - inline void emit_data(int32_t); - inline void emit_data(int32_t, RelocationHolder const&); - inline void emit_data(int32_t, relocInfo::relocType rtype); - - // Helper for the above functions. - inline void check_delay(); - - - public: - // instructions, refer to page numbers in the SPARC Architecture Manual, V9 - - // pp 135 - - inline void add(Register s1, Register s2, Register d); - inline void add(Register s1, int simm13a, Register d); - - inline void addcc(Register s1, Register s2, Register d); - inline void addcc(Register s1, int simm13a, Register d); - inline void addc(Register s1, Register s2, Register d); - inline void addc(Register s1, int simm13a, Register d); - inline void addccc(Register s1, Register s2, Register d); - inline void addccc(Register s1, int simm13a, Register d); - - - // 4-operand AES instructions - - inline void aes_eround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_eround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_dround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_dround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_eround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_eround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_dround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_dround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void aes_kexpand1(FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d); - - - // 3-operand AES instructions - - inline void aes_kexpand0(FloatRegister s1, FloatRegister s2, FloatRegister d); - inline void aes_kexpand2(FloatRegister s1, FloatRegister s2, FloatRegister d); - - // pp 136 - - inline void bpr(RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt = relocInfo::none); - inline void bpr(RCondition c, bool a, Predict p, Register s1, Label &L); - - // compare and branch - inline void cbcond(Condition c, CC cc, Register s1, Register s2, Label &L); - inline void cbcond(Condition c, CC cc, Register s1, int simm5, Label &L); - - protected: // use MacroAssembler::br instead - - // pp 138 - - inline void fb(Condition c, bool a, address d, relocInfo::relocType rt = relocInfo::none); - inline void fb(Condition c, bool a, Label &L); - - // pp 141 - - inline void fbp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none); - inline void fbp(Condition c, bool a, CC cc, Predict p, Label &L); - - // pp 144 - - inline void br(Condition c, bool a, address d, relocInfo::relocType rt = relocInfo::none); - inline void br(Condition c, bool a, Label &L); - - // pp 146 - - inline void bp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none); - inline void bp(Condition c, bool a, CC cc, Predict p, Label &L); - - // pp 149 - - inline void call(address d, relocInfo::relocType rt = relocInfo::runtime_call_type); - inline void call(Label &L, relocInfo::relocType rt = relocInfo::runtime_call_type); - - inline void call(address d, RelocationHolder const &rspec); - - public: - - // pp 150 - - // These instructions compare the contents of s2 with the contents of - // memory at address in s1. If the values are equal, the contents of memory - // at address s1 is swapped with the data in d. If the values are not equal, - // the the contents of memory at s1 is loaded into d, without the swap. - - inline void casa(Register s1, Register s2, Register d, int ia = -1); - inline void casxa(Register s1, Register s2, Register d, int ia = -1); - - // pp 152 - - inline void udiv(Register s1, Register s2, Register d); - inline void udiv(Register s1, int simm13a, Register d); - inline void sdiv(Register s1, Register s2, Register d); - inline void sdiv(Register s1, int simm13a, Register d); - inline void udivcc(Register s1, Register s2, Register d); - inline void udivcc(Register s1, int simm13a, Register d); - inline void sdivcc(Register s1, Register s2, Register d); - inline void sdivcc(Register s1, int simm13a, Register d); - - // pp 155 - - inline void done(); - inline void retry(); - - // pp 156 - - inline void fadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d); - inline void fsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d); - - // pp 157 - - inline void fcmp(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2); - inline void fcmpe(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2); - - // pp 159 - - inline void ftox(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - inline void ftoi(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - - // pp 160 - - inline void ftof(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d); - - // pp 161 - - inline void fxtof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - inline void fitof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - - // pp 162 - - inline void fmov(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - - inline void fneg(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - - inline void fabs(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - - // pp 163 - - inline void fmul(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d); - inline void fmul(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d); - inline void fdiv(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d); - - // FXORs/FXORd instructions - - inline void fxor(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d); - - // pp 164 - - inline void fsqrt(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d); - - // fmaf instructions. - - inline void fmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void fmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - - inline void fnmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - inline void fnmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d); - - // pp 165 - - inline void flush(Register s1, Register s2); - inline void flush(Register s1, int simm13a); - - // pp 167 - - void flushw(); - - // pp 168 - - void illtrap(int const22a); - - // pp 169 - - void impdep1(int id1, int const19a); - void impdep2(int id1, int const19a); - - // pp 170 - - void jmpl(Register s1, Register s2, Register d); - void jmpl(Register s1, int simm13a, Register d, - RelocationHolder const &rspec = RelocationHolder()); - - // 171 - - inline void ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d); - inline void ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, - RelocationHolder const &rspec = RelocationHolder()); - - inline void ldd(Register s1, Register s2, FloatRegister d); - inline void ldd(Register s1, int simm13a, FloatRegister d); - - inline void ldfsr(Register s1, Register s2); - inline void ldfsr(Register s1, int simm13a); - inline void ldxfsr(Register s1, Register s2); - inline void ldxfsr(Register s1, int simm13a); - - // 173 - - inline void ldfa(FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d); - inline void ldfa(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d); - - // pp 175 - - inline void ldsb(Register s1, Register s2, Register d); - inline void ldsb(Register s1, int simm13a, Register d); - inline void ldsh(Register s1, Register s2, Register d); - inline void ldsh(Register s1, int simm13a, Register d); - inline void ldsw(Register s1, Register s2, Register d); - inline void ldsw(Register s1, int simm13a, Register d); - inline void ldub(Register s1, Register s2, Register d); - inline void ldub(Register s1, int simm13a, Register d); - inline void lduh(Register s1, Register s2, Register d); - inline void lduh(Register s1, int simm13a, Register d); - inline void lduw(Register s1, Register s2, Register d); - inline void lduw(Register s1, int simm13a, Register d); - inline void ldx(Register s1, Register s2, Register d); - inline void ldx(Register s1, int simm13a, Register d); - - // pp 177 - - inline void ldsba(Register s1, Register s2, int ia, Register d); - inline void ldsba(Register s1, int simm13a, Register d); - inline void ldsha(Register s1, Register s2, int ia, Register d); - inline void ldsha(Register s1, int simm13a, Register d); - inline void ldswa(Register s1, Register s2, int ia, Register d); - inline void ldswa(Register s1, int simm13a, Register d); - inline void lduba(Register s1, Register s2, int ia, Register d); - inline void lduba(Register s1, int simm13a, Register d); - inline void lduha(Register s1, Register s2, int ia, Register d); - inline void lduha(Register s1, int simm13a, Register d); - inline void lduwa(Register s1, Register s2, int ia, Register d); - inline void lduwa(Register s1, int simm13a, Register d); - inline void ldxa(Register s1, Register s2, int ia, Register d); - inline void ldxa(Register s1, int simm13a, Register d); - - // pp 181 - - inline void and3(Register s1, Register s2, Register d); - inline void and3(Register s1, int simm13a, Register d); - inline void andcc(Register s1, Register s2, Register d); - inline void andcc(Register s1, int simm13a, Register d); - inline void andn(Register s1, Register s2, Register d); - inline void andn(Register s1, int simm13a, Register d); - inline void andncc(Register s1, Register s2, Register d); - inline void andncc(Register s1, int simm13a, Register d); - inline void or3(Register s1, Register s2, Register d); - inline void or3(Register s1, int simm13a, Register d); - inline void orcc(Register s1, Register s2, Register d); - inline void orcc(Register s1, int simm13a, Register d); - inline void orn(Register s1, Register s2, Register d); - inline void orn(Register s1, int simm13a, Register d); - inline void orncc(Register s1, Register s2, Register d); - inline void orncc(Register s1, int simm13a, Register d); - inline void xor3(Register s1, Register s2, Register d); - inline void xor3(Register s1, int simm13a, Register d); - inline void xorcc(Register s1, Register s2, Register d); - inline void xorcc(Register s1, int simm13a, Register d); - inline void xnor(Register s1, Register s2, Register d); - inline void xnor(Register s1, int simm13a, Register d); - inline void xnorcc(Register s1, Register s2, Register d); - inline void xnorcc(Register s1, int simm13a, Register d); - - // pp 183 - - inline void membar(Membar_mask_bits const7a); - - // pp 185 - - inline void fmov(FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d); - - // pp 189 - - inline void fmov(FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d); - - // pp 191 - - inline void movcc(Condition c, bool floatCC, CC cca, Register s2, Register d); - inline void movcc(Condition c, bool floatCC, CC cca, int simm11a, Register d); - - // pp 195 - - inline void movr(RCondition c, Register s1, Register s2, Register d); - inline void movr(RCondition c, Register s1, int simm10a, Register d); - - // pp 196 - - inline void mulx(Register s1, Register s2, Register d); - inline void mulx(Register s1, int simm13a, Register d); - inline void sdivx(Register s1, Register s2, Register d); - inline void sdivx(Register s1, int simm13a, Register d); - inline void udivx(Register s1, Register s2, Register d); - inline void udivx(Register s1, int simm13a, Register d); - - // pp 197 - - inline void umul(Register s1, Register s2, Register d); - inline void umul(Register s1, int simm13a, Register d); - inline void smul(Register s1, Register s2, Register d); - inline void smul(Register s1, int simm13a, Register d); - inline void umulcc(Register s1, Register s2, Register d); - inline void umulcc(Register s1, int simm13a, Register d); - inline void smulcc(Register s1, Register s2, Register d); - inline void smulcc(Register s1, int simm13a, Register d); - - // pp 201 - - inline void nop(); - - inline void sw_count(); - - // pp 202 - - inline void popc(Register s, Register d); - inline void popc(int simm13a, Register d); - - // pp 203 - - inline void prefetch(Register s1, Register s2, PrefetchFcn f); - inline void prefetch(Register s1, int simm13a, PrefetchFcn f); - - inline void prefetcha(Register s1, Register s2, int ia, PrefetchFcn f); - inline void prefetcha(Register s1, int simm13a, PrefetchFcn f); - - // pp 208 - - // not implementing read privileged register - - inline void rdy(Register d); - inline void rdccr(Register d); - inline void rdasi(Register d); - inline void rdtick(Register d); - inline void rdpc(Register d); - inline void rdfprs(Register d); - - // pp 213 - - inline void rett(Register s1, Register s2); - inline void rett(Register s1, int simm13a, relocInfo::relocType rt = relocInfo::none); - - // pp 214 - - inline void save(Register s1, Register s2, Register d); - inline void save(Register s1, int simm13a, Register d); - - inline void restore(Register s1 = G0, Register s2 = G0, Register d = G0); - inline void restore(Register s1, int simm13a, Register d); - - // pp 216 - - inline void saved(); - inline void restored(); - - // pp 217 - - inline void sethi(int imm22a, Register d, RelocationHolder const &rspec = RelocationHolder()); - - // pp 218 - - inline void sll(Register s1, Register s2, Register d); - inline void sll(Register s1, int imm5a, Register d); - inline void srl(Register s1, Register s2, Register d); - inline void srl(Register s1, int imm5a, Register d); - inline void sra(Register s1, Register s2, Register d); - inline void sra(Register s1, int imm5a, Register d); - - inline void sllx(Register s1, Register s2, Register d); - inline void sllx(Register s1, int imm6a, Register d); - inline void srlx(Register s1, Register s2, Register d); - inline void srlx(Register s1, int imm6a, Register d); - inline void srax(Register s1, Register s2, Register d); - inline void srax(Register s1, int imm6a, Register d); - - // pp 220 - - inline void sir(int simm13a); - - // pp 221 - - inline void stbar(); - - // pp 222 - - inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2); - inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a); - - inline void std(FloatRegister d, Register s1, Register s2); - inline void std(FloatRegister d, Register s1, int simm13a); - - inline void stfsr(Register s1, Register s2); - inline void stfsr(Register s1, int simm13a); - inline void stxfsr(Register s1, Register s2); - inline void stxfsr(Register s1, int simm13a); - - // pp 224 - - inline void stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia); - inline void stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a); - - // pp 226 - - inline void stb(Register d, Register s1, Register s2); - inline void stb(Register d, Register s1, int simm13a); - inline void sth(Register d, Register s1, Register s2); - inline void sth(Register d, Register s1, int simm13a); - inline void stw(Register d, Register s1, Register s2); - inline void stw(Register d, Register s1, int simm13a); - inline void stx(Register d, Register s1, Register s2); - inline void stx(Register d, Register s1, int simm13a); - - // pp 177 - - inline void stba(Register d, Register s1, Register s2, int ia); - inline void stba(Register d, Register s1, int simm13a); - inline void stha(Register d, Register s1, Register s2, int ia); - inline void stha(Register d, Register s1, int simm13a); - inline void stwa(Register d, Register s1, Register s2, int ia); - inline void stwa(Register d, Register s1, int simm13a); - inline void stxa(Register d, Register s1, Register s2, int ia); - inline void stxa(Register d, Register s1, int simm13a); - inline void stda(Register d, Register s1, Register s2, int ia); - inline void stda(Register d, Register s1, int simm13a); - - // pp 230 - - inline void sub(Register s1, Register s2, Register d); - inline void sub(Register s1, int simm13a, Register d); - - inline void subcc(Register s1, Register s2, Register d); - inline void subcc(Register s1, int simm13a, Register d); - inline void subc(Register s1, Register s2, Register d); - inline void subc(Register s1, int simm13a, Register d); - inline void subccc(Register s1, Register s2, Register d); - inline void subccc(Register s1, int simm13a, Register d); - - // pp 231 - - inline void swap(Register s1, Register s2, Register d); - inline void swap(Register s1, int simm13a, Register d); - - // pp 232 - - inline void swapa(Register s1, Register s2, int ia, Register d); - inline void swapa(Register s1, int simm13a, Register d); - - // pp 234, note op in book is wrong, see pp 268 - - inline void taddcc(Register s1, Register s2, Register d); - inline void taddcc(Register s1, int simm13a, Register d); - - // pp 235 - - inline void tsubcc(Register s1, Register s2, Register d); - inline void tsubcc(Register s1, int simm13a, Register d); - - // pp 237 - - inline void trap(Condition c, CC cc, Register s1, Register s2); - inline void trap(Condition c, CC cc, Register s1, int trapa); - // simple uncond. trap - inline void trap(int trapa); - - // pp 239 omit write priv register for now - - inline void wry(Register d); - inline void wrccr(Register s); - inline void wrccr(Register s, int simm13a); - inline void wrasi(Register d); - // wrasi(d, imm) stores (d xor imm) to asi - inline void wrasi(Register d, int simm13a); - inline void wrfprs(Register d); - - // VIS1 instructions - - inline void alignaddr(Register s1, Register s2, Register d); - - inline void faligndata(FloatRegister s1, FloatRegister s2, FloatRegister d); - - inline void fzero(FloatRegisterImpl::Width w, FloatRegister d); - - inline void fsrc2(FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d); - - inline void fnot1(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d); - - inline void fpmerge(FloatRegister s1, FloatRegister s2, FloatRegister d); - - inline void stpartialf(Register s1, Register s2, FloatRegister d, int ia = -1); - - // VIS2 instructions - - inline void edge8n(Register s1, Register s2, Register d); - - inline void bmask(Register s1, Register s2, Register d); - inline void bshuffle(FloatRegister s1, FloatRegister s2, FloatRegister d); - - // VIS3 instructions - - inline void addxc(Register s1, Register s2, Register d); - inline void addxccc(Register s1, Register s2, Register d); - - inline void movstosw(FloatRegister s, Register d); - inline void movstouw(FloatRegister s, Register d); - inline void movdtox(FloatRegister s, Register d); - - inline void movwtos(Register s, FloatRegister d); - inline void movxtod(Register s, FloatRegister d); - - inline void xmulx(Register s1, Register s2, Register d); - inline void xmulxhi(Register s1, Register s2, Register d); - inline void umulxhi(Register s1, Register s2, Register d); - - // Crypto SHA instructions - - inline void sha1(); - inline void sha256(); - inline void sha512(); - - // CRC32C instruction - - inline void crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d); - - // MPMUL instruction - - inline void mpmul(int uimm5); - - // Creation - Assembler(CodeBuffer* code) : AbstractAssembler(code) { -#ifdef VALIDATE_PIPELINE - _delay_state = NoDelay; - _hazard_state = NoHazard; -#endif - } -}; - -#endif // CPU_SPARC_ASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp b/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/assembler_sparc.inline.hpp +++ /dev/null @@ -1,1130 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_ASSEMBLER_SPARC_INLINE_HPP -#define CPU_SPARC_ASSEMBLER_SPARC_INLINE_HPP - -#include "asm/assembler.hpp" - - -inline void Assembler::avoid_pipeline_stall() { -#ifdef VALIDATE_PIPELINE - if (_hazard_state == PcHazard) { - assert(is_cbcond_before() || is_rdpc_before(), "PC-hazard not preceeded by CBCOND or RDPC."); - assert_no_delay("Must not have PC-hazard state in delay-slot."); - nop(); - _hazard_state = NoHazard; - } -#endif - - bool post_cond = is_cbcond_before(); - bool post_rdpc = is_rdpc_before(); - - if (post_cond || post_rdpc) { - nop(); -#ifdef VALIDATE_PIPELINE - if (_hazard_state != PcHazard) { - assert(post_cond, "CBCOND before when no hazard @0x%p\n", pc()); - assert(post_rdpc, "RDPC before when no hazard @0x%p\n", pc()); - } -#endif - } -} - -inline void Assembler::check_delay() { -#ifdef VALIDATE_PIPELINE - guarantee(_delay_state != AtDelay, "Use delayed() when filling delay-slot"); - _delay_state = NoDelay; -#endif -} - -inline void Assembler::emit_int32(int32_t x) { - check_delay(); -#ifdef VALIDATE_PIPELINE - _hazard_state = NoHazard; -#endif - AbstractAssembler::emit_int32(x); -} - -inline void Assembler::emit_data(int32_t x) { - emit_int32(x); -} - -inline void Assembler::emit_data(int32_t x, relocInfo::relocType rtype) { - relocate(rtype); - emit_int32(x); -} - -inline void Assembler::emit_data(int32_t x, RelocationHolder const &rspec) { - relocate(rspec); - emit_int32(x); -} - - -inline void Assembler::add(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::add(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::addcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::addcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::addc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(addc_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::addc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(addc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::addccc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::addccc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::aes_eround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_eround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_dround01(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_dround23(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_eround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_l_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_eround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_l_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_dround01_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_l_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_dround23_l(FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_l_op5) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_kexpand1(FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | u_field(imm5a, 13, 9) | op5(aes_kexpand1_op5) | fs2(s2, FloatRegisterImpl::D)); -} - -// 3-operand AES instructions - -inline void Assembler::aes_kexpand0(FloatRegister s1, FloatRegister s2, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand0_opf) | fs2(s2, FloatRegisterImpl::D)); -} -inline void Assembler::aes_kexpand2(FloatRegister s1, FloatRegister s2, FloatRegister d) { - aes_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand2_opf) | fs2(s2, FloatRegisterImpl::D)); -} - -inline void Assembler::bpr(RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt) { - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | annul(a) | cond(c) | op2(bpr_op2) | wdisp16(intptr_t(d), intptr_t(pc())) | predict(p) | rs1(s1), rt); - induce_delay_slot(); -} -inline void Assembler::bpr(RCondition c, bool a, Predict p, Register s1, Label &L) { - // Note[+]: All assembly emit routines using the 'target()' branch back-patch - // resolver must call 'avoid_pipeline_stall()' prior to calling 'target()' - // (we must do so even though the call will be made, as here, in the above - // implementation of 'bpr()', invoked below). The reason is the assumption - // made in 'target()', where using the current PC as the address for back- - // patching prevents any additional code to be emitted _after_ the address - // has been set (implicitly) in order to refer to the correct instruction. - avoid_pipeline_stall(); - bpr(c, a, p, s1, target(L)); -} - -inline void Assembler::fb(Condition c, bool a, address d, relocInfo::relocType rt) { - v9_dep(); - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | annul(a) | cond(c) | op2(fb_op2) | wdisp(intptr_t(d), intptr_t(pc()), 22), rt); - induce_delay_slot(); -} -inline void Assembler::fb(Condition c, bool a, Label &L) { - avoid_pipeline_stall(); - fb(c, a, target(L)); -} - -inline void Assembler::fbp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt) { - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | annul(a) | cond(c) | op2(fbp_op2) | branchcc(cc) | predict(p) | wdisp(intptr_t(d), intptr_t(pc()), 19), rt); - induce_delay_slot(); -} -inline void Assembler::fbp(Condition c, bool a, CC cc, Predict p, Label &L) { - avoid_pipeline_stall(); - fbp(c, a, cc, p, target(L)); -} - -inline void Assembler::br(Condition c, bool a, address d, relocInfo::relocType rt) { - v9_dep(); - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | annul(a) | cond(c) | op2(br_op2) | wdisp(intptr_t(d), intptr_t(pc()), 22), rt); - induce_delay_slot(); -} -inline void Assembler::br(Condition c, bool a, Label &L) { - avoid_pipeline_stall(); - br(c, a, target(L)); -} - -inline void Assembler::bp(Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt) { - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | annul(a) | cond(c) | op2(bp_op2) | branchcc(cc) | predict(p) | wdisp(intptr_t(d), intptr_t(pc()), 19), rt); - induce_delay_slot(); -} -inline void Assembler::bp(Condition c, bool a, CC cc, Predict p, Label &L) { - avoid_pipeline_stall(); - bp(c, a, cc, p, target(L)); -} - -// compare and branch -inline void Assembler::cbcond(Condition c, CC cc, Register s1, Register s2, Label &L) { - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | cond_cbcond(c) | op2(bpr_op2) | branchcc(cc) | wdisp10(intptr_t(target(L)), intptr_t(pc())) | rs1(s1) | rs2(s2)); - induce_pc_hazard(); -} -inline void Assembler::cbcond(Condition c, CC cc, Register s1, int simm5, Label &L) { - avoid_pipeline_stall(); - cti(); - emit_data(op(branch_op) | cond_cbcond(c) | op2(bpr_op2) | branchcc(cc) | wdisp10(intptr_t(target(L)), intptr_t(pc())) | rs1(s1) | immed(true) | simm(simm5, 5)); - induce_pc_hazard(); -} - -inline void Assembler::call(address d, relocInfo::relocType rt) { - avoid_pipeline_stall(); - cti(); - emit_data(op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt); - induce_delay_slot(); - assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); -} -inline void Assembler::call(Label &L, relocInfo::relocType rt) { - avoid_pipeline_stall(); - call(target(L), rt); -} - -inline void Assembler::call(address d, RelocationHolder const &rspec) { - avoid_pipeline_stall(); - cti(); - emit_data(op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rspec); - induce_delay_slot(); - assert(rspec.type() != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); -} - -inline void Assembler::casa(Register s1, Register s2, Register d, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(casa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); -} -inline void Assembler::casxa(Register s1, Register s2, Register d, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); -} - -inline void Assembler::udiv(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(udiv_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::udiv(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(udiv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::sdiv(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::sdiv(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::udivcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::udivcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::sdivcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::sdivcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::done() { - cti(); - emit_int32(op(arith_op) | fcn(0) | op3(done_op3)); -} -inline void Assembler::retry() { - cti(); - emit_int32(op(arith_op) | fcn(1) | op3(retry_op3)); -} - -inline void Assembler::fadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); -} -inline void Assembler::fsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); -} - -inline void Assembler::fcmp(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { - emit_int32(op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); -} -inline void Assembler::fcmpe(FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { - emit_int32(op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); -} - -inline void Assembler::ftox(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); -} -inline void Assembler::ftoi(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); -} - -inline void Assembler::ftof(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); -} - -inline void Assembler::fxtof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); -} -inline void Assembler::fitof(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); -} - -inline void Assembler::fmov(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); -} -inline void Assembler::fneg(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); -} -inline void Assembler::fabs(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); -} -inline void Assembler::fmul(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); -} -inline void Assembler::fmul(FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); -} -inline void Assembler::fdiv(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); -} - -inline void Assembler::fxor(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d) { - vis1_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(flog3_op3) | fs1(s1, w) | opf(0x6E - w) | fs2(s2, w)); -} - -inline void Assembler::fsqrt(FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); -} - -inline void Assembler::fmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - fmaf_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(w) | fs2(s2, w)); -} -inline void Assembler::fmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - fmaf_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0x4 + w) | fs2(s2, w)); -} - -inline void Assembler::fnmadd(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - fmaf_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0xc + w) | fs2(s2, w)); -} -inline void Assembler::fnmsub(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d) { - fmaf_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(stpartialf_op3) | fs1(s1, w) | fs3(s3, w) | op5(0x8 + w) | fs2(s2, w)); -} - -inline void Assembler::flush(Register s1, Register s2) { - emit_int32(op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::flush(Register s1, int simm13a) { - emit_data(op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::flushw() { - emit_int32(op(arith_op) | op3(flushw_op3)); -} - -inline void Assembler::illtrap(int const22a) { - emit_int32(op(branch_op) | u_field(const22a, 21, 0)); -} - -inline void Assembler::impdep1(int id1, int const19a) { - emit_int32(op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); -} -inline void Assembler::impdep2(int id1, int const19a) { - emit_int32(op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); -} - -inline void Assembler::jmpl(Register s1, Register s2, Register d) { - avoid_pipeline_stall(); - cti(); - emit_int32(op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | rs2(s2)); - induce_delay_slot(); -} -inline void Assembler::jmpl(Register s1, int simm13a, Register d, RelocationHolder const &rspec) { - avoid_pipeline_stall(); - cti(); - emit_data(op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); - induce_delay_slot(); -} - -inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { - emit_int32(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const &rspec) { - emit_data(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); -} - -inline void Assembler::ldd(Register s1, Register s2, FloatRegister d) { - assert(d->is_even(), "not even"); - ldf(FloatRegisterImpl::D, s1, s2, d); -} -inline void Assembler::ldd(Register s1, int simm13a, FloatRegister d) { - assert(d->is_even(), "not even"); - ldf(FloatRegisterImpl::D, s1, simm13a, d); -} - -inline void Assembler::ldxfsr(Register s1, Register s2) { - emit_int32(op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldxfsr(Register s1, int simm13a) { - emit_data(op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::ldfa(FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d) { - emit_int32(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::ldfa(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d) { - emit_int32(op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::ldsb(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldsb(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::ldsh(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldsh(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::ldsw(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldsw(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::ldub(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldub(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::lduh(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::lduh(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::lduw(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::lduw(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::ldx(Register s1, Register s2, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::ldx(Register s1, int simm13a, Register d) { - emit_data(op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::ldsba(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::ldsba(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::ldsha(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::ldsha(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::ldswa(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::ldswa(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::lduba(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::lduba(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::lduha(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::lduha(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::lduwa(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::lduwa(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::ldxa(Register s1, Register s2, int ia, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::ldxa(Register s1, int simm13a, Register d) { - emit_int32(op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::and3(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(and_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::and3(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(and_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::andcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::andcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::andn(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(andn_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::andn(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(andn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::andncc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::andncc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::or3(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(or_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::or3(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(or_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::orcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::orcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::orn(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::orn(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::orncc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::orncc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::xor3(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xor_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::xor3(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xor_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::xorcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::xorcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::xnor(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xnor_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::xnor(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xnor_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::xnorcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::xnorcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::membar(Membar_mask_bits const7a) { - emit_int32(op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field(int(const7a), 6, 0)); -} - -inline void Assembler::fmov(FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); -} - -inline void Assembler::fmov(FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d) { - emit_int32(op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); -} - -inline void Assembler::movcc(Condition c, bool floatCC, CC cca, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2)); -} -inline void Assembler::movcc(Condition c, bool floatCC, CC cca, int simm11a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11)); -} - -inline void Assembler::movr(RCondition c, Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2)); -} -inline void Assembler::movr(RCondition c, Register s1, int simm10a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10)); -} - -inline void Assembler::mulx(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(mulx_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::mulx(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(mulx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::sdivx(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::sdivx(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::udivx(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::udivx(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::umul(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(umul_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::umul(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(umul_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::smul(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(smul_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::smul(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(smul_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::umulcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::umulcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::smulcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::smulcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::nop() { - emit_int32(op(branch_op) | op2(sethi_op2)); -} - -inline void Assembler::sw_count() { - emit_int32(op(branch_op) | op2(sethi_op2) | 0x3f0); -} - -inline void Assembler::popc(Register s, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); -} -inline void Assembler::popc(int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::prefetch(Register s1, Register s2, PrefetchFcn f) { - emit_int32(op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::prefetch(Register s1, int simm13a, PrefetchFcn f) { - emit_data(op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::prefetcha(Register s1, Register s2, int ia, PrefetchFcn f) { - emit_int32(op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::prefetcha(Register s1, int simm13a, PrefetchFcn f) { - emit_int32(op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::rdy(Register d) { - v9_dep(); - emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); -} -inline void Assembler::rdccr(Register d) { - emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); -} -inline void Assembler::rdasi(Register d) { - emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); -} -inline void Assembler::rdtick(Register d) { - emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); -} -inline void Assembler::rdpc(Register d) { - avoid_pipeline_stall(); - cti(); - emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); - induce_pc_hazard(); -} -inline void Assembler::rdfprs(Register d) { - emit_int32(op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); -} - -inline void Assembler::rett(Register s1, Register s2) { - cti(); - emit_int32(op(arith_op) | op3(rett_op3) | rs1(s1) | rs2(s2)); - induce_delay_slot(); -} -inline void Assembler::rett(Register s1, int simm13a, relocInfo::relocType rt) { - cti(); - emit_data(op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt); - induce_delay_slot(); -} - -inline void Assembler::save(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::save(Register s1, int simm13a, Register d) { - // make sure frame is at least large enough for the register save area - assert(-simm13a >= 16 * wordSize, "frame too small"); - emit_int32(op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::restore(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::restore(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// pp 216 - -inline void Assembler::saved() { - emit_int32(op(arith_op) | fcn(0) | op3(saved_op3)); -} -inline void Assembler::restored() { - emit_int32(op(arith_op) | fcn(1) | op3(saved_op3)); -} - -inline void Assembler::sethi(int imm22a, Register d, RelocationHolder const &rspec) { - emit_data(op(branch_op) | rd(d) | op2(sethi_op2) | hi22(imm22a), rspec); -} - -inline void Assembler::sll(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2)); -} -inline void Assembler::sll(Register s1, int imm5a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0)); -} -inline void Assembler::srl(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2)); -} -inline void Assembler::srl(Register s1, int imm5a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0)); -} -inline void Assembler::sra(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2)); -} -inline void Assembler::sra(Register s1, int imm5a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0)); -} - -inline void Assembler::sllx(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2)); -} -inline void Assembler::sllx(Register s1, int imm6a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0)); -} -inline void Assembler::srlx(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2)); -} -inline void Assembler::srlx(Register s1, int imm6a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0)); -} -inline void Assembler::srax(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2)); -} -inline void Assembler::srax(Register s1, int imm6a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0)); -} - -inline void Assembler::sir(int simm13a) { - emit_int32(op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); -} - -// pp 221 - -inline void Assembler::stbar() { - emit_int32(op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); -} - -// pp 222 - -inline void Assembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2) { - emit_int32(op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | rs2(s2)); -} -inline void Assembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) { - emit_data(op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::std(FloatRegister d, Register s1, Register s2) { - assert(d->is_even(), "not even"); - stf(FloatRegisterImpl::D, d, s1, s2); -} -inline void Assembler::std(FloatRegister d, Register s1, int simm13a) { - assert(d->is_even(), "not even"); - stf(FloatRegisterImpl::D, d, s1, simm13a); -} - -inline void Assembler::stxfsr(Register s1, Register s2) { - emit_int32(op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::stxfsr(Register s1, int simm13a) { - emit_data(op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia) { - emit_int32(op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::stfa(FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a) { - emit_int32(op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// p 226 - -inline void Assembler::stb(Register d, Register s1, Register s2) { - emit_int32(op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::stb(Register d, Register s1, int simm13a) { - emit_data(op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::sth(Register d, Register s1, Register s2) { - emit_int32(op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::sth(Register d, Register s1, int simm13a) { - emit_data(op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::stw(Register d, Register s1, Register s2) { - emit_int32(op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::stw(Register d, Register s1, int simm13a) { - emit_data(op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - - -inline void Assembler::stx(Register d, Register s1, Register s2) { - emit_int32(op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::stx(Register d, Register s1, int simm13a) { - emit_data(op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::stba(Register d, Register s1, Register s2, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::stba(Register d, Register s1, int simm13a) { - emit_int32(op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::stha(Register d, Register s1, Register s2, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::stha(Register d, Register s1, int simm13a) { - emit_int32(op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::stwa(Register d, Register s1, Register s2, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::stwa(Register d, Register s1, int simm13a) { - emit_int32(op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::stxa(Register d, Register s1, Register s2, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::stxa(Register d, Register s1, int simm13a) { - emit_int32(op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::stda(Register d, Register s1, Register s2, int ia) { - emit_int32(op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::stda(Register d, Register s1, int simm13a) { - emit_int32(op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// pp 230 - -inline void Assembler::sub(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sub_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::sub(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::subcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::subcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::subc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(subc_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::subc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(subc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::subccc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::subccc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// pp 231 - -inline void Assembler::swap(Register s1, Register s2, Register d) { - v9_dep(); - emit_int32(op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::swap(Register s1, int simm13a, Register d) { - v9_dep(); - emit_data(op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -inline void Assembler::swapa(Register s1, Register s2, int ia, Register d) { - v9_dep(); - emit_int32(op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} -inline void Assembler::swapa(Register s1, int simm13a, Register d) { - v9_dep(); - emit_int32(op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// pp 234, note op in book is wrong, see pp 268 - -inline void Assembler::taddcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(taddcc_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::taddcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(taddcc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// pp 235 - -inline void Assembler::tsubcc(Register s1, Register s2, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(tsubcc_op3) | rs1(s1) | rs2(s2)); -} -inline void Assembler::tsubcc(Register s1, int simm13a, Register d) { - emit_int32(op(arith_op) | rd(d) | op3(tsubcc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); -} - -// pp 237 - -inline void Assembler::trap(Condition c, CC cc, Register s1, Register s2) { - emit_int32(op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); -} -inline void Assembler::trap(Condition c, CC cc, Register s1, int trapa) { - emit_int32(op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); -} -// simple uncond. trap -inline void Assembler::trap(int trapa) { - trap(always, icc, G0, trapa); -} - -inline void Assembler::wry(Register d) { - v9_dep(); - emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); -} -inline void Assembler::wrccr(Register s) { - emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); -} -inline void Assembler::wrccr(Register s, int simm13a) { - emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::wrasi(Register d) { - emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); -} -// wrasi(d, imm) stores (d xor imm) to asi -inline void Assembler::wrasi(Register d, int simm13a) { - emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); -} -inline void Assembler::wrfprs(Register d) { - emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); -} - -inline void Assembler::alignaddr(Register s1, Register s2, Register d) { - vis1_only(); - emit_int32(op(arith_op) | rd(d) | op3(alignaddr_op3) | rs1(s1) | opf(alignaddr_opf) | rs2(s2)); -} - -inline void Assembler::faligndata(FloatRegister s1, FloatRegister s2, FloatRegister d) { - vis1_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D)); -} - -inline void Assembler::fzero(FloatRegisterImpl::Width w, FloatRegister d) { - vis1_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w)); -} - -inline void Assembler::fsrc2(FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d) { - vis1_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w)); -} - -inline void Assembler::fnot1(FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d) { - vis1_only(); - emit_int32(op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w)); -} - -inline void Assembler::fpmerge(FloatRegister s1, FloatRegister s2, FloatRegister d) { - vis1_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S)); -} - -inline void Assembler::stpartialf(Register s1, Register s2, FloatRegister d, int ia) { - vis1_only(); - emit_int32(op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); -} - -// VIS2 instructions - -inline void Assembler::edge8n(Register s1, Register s2, Register d) { - vis2_only(); - emit_int32(op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2)); -} - -inline void Assembler::bmask(Register s1, Register s2, Register d) { - vis2_only(); - emit_int32(op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2)); -} -inline void Assembler::bshuffle(FloatRegister s1, FloatRegister s2, FloatRegister d) { - vis2_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D)); -} - -// VIS3 instructions - -inline void Assembler::addxc(Register s1, Register s2, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(addx_op3) | rs1(s1) | opf(addxc_opf) | rs2(s2)); -} -inline void Assembler::addxccc(Register s1, Register s2, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(addx_op3) | rs1(s1) | opf(addxccc_opf) | rs2(s2)); -} - -inline void Assembler::movstosw(FloatRegister s, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); -} -inline void Assembler::movstouw(FloatRegister s, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); -} -inline void Assembler::movdtox(FloatRegister s, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); -} - -inline void Assembler::movwtos(Register s, FloatRegister d) { - vis3_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); -} -inline void Assembler::movxtod(Register s, FloatRegister d) { - vis3_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); -} - -inline void Assembler::xmulx(Register s1, Register s2, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2)); -} -inline void Assembler::xmulxhi(Register s1, Register s2, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); -} -inline void Assembler::umulxhi(Register s1, Register s2, Register d) { - vis3_only(); - emit_int32(op(arith_op) | rd(d) | op3(umulx_op3) | rs1(s1) | opf(umulxhi_opf) | rs2(s2)); -} - -// Crypto SHA instructions - -inline void Assembler::sha1() { - sha1_only(); - emit_int32(op(arith_op) | op3(sha_op3) | opf(sha1_opf)); -} -inline void Assembler::sha256() { - sha256_only(); - emit_int32(op(arith_op) | op3(sha_op3) | opf(sha256_opf)); -} -inline void Assembler::sha512() { - sha512_only(); - emit_int32(op(arith_op) | op3(sha_op3) | opf(sha512_opf)); -} - -// CRC32C instruction - -inline void Assembler::crc32c(FloatRegister s1, FloatRegister s2, FloatRegister d) { - crc32c_only(); - emit_int32(op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); -} - -// MPMUL instruction - -inline void Assembler::mpmul(int uimm5) { - mpmul_only(); - emit_int32(op(arith_op) | rd(0) | op3(mpmul_op3) | rs1(0) | opf(mpmul_opf) | uimm(uimm5, 5)); -} - -#endif // CPU_SPARC_ASSEMBLER_SPARC_INLINE_HPP diff --git a/src/hotspot/cpu/sparc/bytes_sparc.hpp b/src/hotspot/cpu/sparc/bytes_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/bytes_sparc.hpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_BYTES_SPARC_HPP -#define CPU_SPARC_BYTES_SPARC_HPP - -#include "memory/allocation.hpp" - -class Bytes: AllStatic { - public: - // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering - // Sparc needs to check for alignment. - - // can I count on address always being a pointer to an unsigned char? Yes - - // Thus, a swap between native and Java ordering is always a no-op: - static inline u2 swap_u2(u2 x) { return x; } - static inline u4 swap_u4(u4 x) { return x; } - static inline u8 swap_u8(u8 x) { return x; } - - static inline u2 get_native_u2(address p){ - return (intptr_t(p) & 1) == 0 - ? *(u2*)p - : ( u2(p[0]) << 8 ) - | ( u2(p[1]) ); - } - - static inline u4 get_native_u4(address p) { - switch (intptr_t(p) & 3) { - case 0: return *(u4*)p; - - case 2: return ( u4( ((u2*)p)[0] ) << 16 ) - | ( u4( ((u2*)p)[1] ) ); - - default: return ( u4(p[0]) << 24 ) - | ( u4(p[1]) << 16 ) - | ( u4(p[2]) << 8 ) - | u4(p[3]); - } - } - - static inline u8 get_native_u8(address p) { - switch (intptr_t(p) & 7) { - case 0: return *(u8*)p; - - case 4: return ( u8( ((u4*)p)[0] ) << 32 ) - | ( u8( ((u4*)p)[1] ) ); - - case 2: return ( u8( ((u2*)p)[0] ) << 48 ) - | ( u8( ((u2*)p)[1] ) << 32 ) - | ( u8( ((u2*)p)[2] ) << 16 ) - | ( u8( ((u2*)p)[3] ) ); - - default: return ( u8(p[0]) << 56 ) - | ( u8(p[1]) << 48 ) - | ( u8(p[2]) << 40 ) - | ( u8(p[3]) << 32 ) - | ( u8(p[4]) << 24 ) - | ( u8(p[5]) << 16 ) - | ( u8(p[6]) << 8 ) - | u8(p[7]); - } - } - - - - static inline void put_native_u2(address p, u2 x) { - if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x; - else { - p[0] = x >> 8; - p[1] = x; - } - } - - static inline void put_native_u4(address p, u4 x) { - switch ( intptr_t(p) & 3 ) { - case 0: *(u4*)p = x; - break; - - case 2: ((u2*)p)[0] = x >> 16; - ((u2*)p)[1] = x; - break; - - default: ((u1*)p)[0] = x >> 24; - ((u1*)p)[1] = x >> 16; - ((u1*)p)[2] = x >> 8; - ((u1*)p)[3] = x; - break; - } - } - - static inline void put_native_u8(address p, u8 x) { - switch ( intptr_t(p) & 7 ) { - case 0: *(u8*)p = x; - break; - - case 4: ((u4*)p)[0] = x >> 32; - ((u4*)p)[1] = x; - break; - - case 2: ((u2*)p)[0] = x >> 48; - ((u2*)p)[1] = x >> 32; - ((u2*)p)[2] = x >> 16; - ((u2*)p)[3] = x; - break; - - default: ((u1*)p)[0] = x >> 56; - ((u1*)p)[1] = x >> 48; - ((u1*)p)[2] = x >> 40; - ((u1*)p)[3] = x >> 32; - ((u1*)p)[4] = x >> 24; - ((u1*)p)[5] = x >> 16; - ((u1*)p)[6] = x >> 8; - ((u1*)p)[7] = x; - } - } - - - // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) - // (no byte-order reversal is needed since SPARC CPUs are big-endian oriented) - static inline u2 get_Java_u2(address p) { return get_native_u2(p); } - static inline u4 get_Java_u4(address p) { return get_native_u4(p); } - static inline u8 get_Java_u8(address p) { return get_native_u8(p); } - - static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); } - static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); } - static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); } -}; - -//Reconciliation History -// 1.7 98/02/24 10:18:41 bytes_i486.hpp -// 1.10 98/04/08 18:47:57 bytes_i486.hpp -// 1.13 98/07/15 17:10:03 bytes_i486.hpp -// 1.14 98/08/13 10:38:23 bytes_i486.hpp -// 1.15 98/10/05 16:30:21 bytes_i486.hpp -// 1.17 99/06/22 16:37:35 bytes_i486.hpp -//End - -#endif // CPU_SPARC_BYTES_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp b/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_CodeStubs_sparc.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Copyright (c) 1999, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.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_sparc.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/macros.hpp" -#include "vmreg_sparc.inline.hpp" - -#define __ ce->masm()-> - -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) - : _throw_index_out_of_bounds_exception(false), _index(index), _array(array) { - assert(info != NULL, "must have info"); - _info = new CodeEmitInfo(info); -} - -RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index) - : _throw_index_out_of_bounds_exception(true), _index(index), _array(NULL) { - 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); - __ call(a, relocInfo::runtime_call_type); - __ delayed()->nop(); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); - return; - } - - if (_index->is_register()) { - __ mov(_index->as_register(), G4); - } else { - __ set(_index->as_jint(), G4); - } - if (_throw_index_out_of_bounds_exception) { - __ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type); - } else { - __ mov(_array->as_pointer_register(), G5); - __ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type); - } - __ delayed()->nop(); - 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); - __ call(a, relocInfo::runtime_call_type); - __ delayed()->nop(); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); -} - -void CounterOverflowStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - __ set(_bci, G4); - Metadata *m = _method->as_constant_ptr()->as_metadata(); - __ set_metadata_constant(m, G5); - __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - - __ br(Assembler::always, true, Assembler::pt, _continuation); - __ delayed()->nop(); -} - - -void DivByZeroStub::emit_code(LIR_Assembler* ce) { - if (_offset != -1) { - ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); - } - __ bind(_entry); - __ call(Runtime1::entry_for(Runtime1::throw_div0_exception_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); -#ifdef ASSERT - __ should_not_reach_here(); -#endif -} - - -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); - __ call(a, relocInfo::runtime_call_type); - __ delayed()->nop(); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); -#ifdef ASSERT - __ should_not_reach_here(); -#endif -} - - -// Implementation of SimpleExceptionStub -// Note: %g1 and %g3 are already in use -void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - __ call(Runtime1::entry_for(_stub), relocInfo::runtime_call_type); - - if (_obj->is_valid()) { - __ delayed()->mov(_obj->as_register(), G4); // _obj contains the optional argument to the stub - } else { - __ delayed()->mov(G0, G4); - } - ce->add_call_info_here(_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) { - __ bind(_entry); - __ call(Runtime1::entry_for(_stub_id), relocInfo::runtime_call_type); - __ delayed()->mov_or_nop(_klass_reg->as_register(), G5); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->mov_or_nop(O0, _result->as_register()); -} - - -// 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) { - __ bind(_entry); - - __ mov(_length->as_register(), G4); - __ call(Runtime1::entry_for(Runtime1::new_type_array_id), relocInfo::runtime_call_type); - __ delayed()->mov_or_nop(_klass_reg->as_register(), G5); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->mov_or_nop(O0, _result->as_register()); -} - - -// Implementation of NewObjectArrayStub - -NewObjectArrayStub::NewObjectArrayStub(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 NewObjectArrayStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - - __ mov(_length->as_register(), G4); - __ call(Runtime1::entry_for(Runtime1::new_object_array_id), relocInfo::runtime_call_type); - __ delayed()->mov_or_nop(_klass_reg->as_register(), G5); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->mov_or_nop(O0, _result->as_register()); -} - - -// 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) { - __ bind(_entry); - __ mov(_obj_reg->as_register(), G4); - if (ce->compilation()->has_fpu_code()) { - __ call(Runtime1::entry_for(Runtime1::monitorenter_id), relocInfo::runtime_call_type); - } else { - __ call(Runtime1::entry_for(Runtime1::monitorenter_nofpu_id), relocInfo::runtime_call_type); - } - __ delayed()->mov_or_nop(_lock_reg->as_register(), G5); - ce->add_call_info_here(_info); - ce->verify_oop_map(_info); - __ br(Assembler::always, true, Assembler::pt, _continuation); - __ delayed()->nop(); -} - - -void MonitorExitStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - if (_compute_lock) { - ce->monitor_address(_monitor_ix, _lock_reg); - } - if (ce->compilation()->has_fpu_code()) { - __ call(Runtime1::entry_for(Runtime1::monitorexit_id), relocInfo::runtime_call_type); - } else { - __ call(Runtime1::entry_for(Runtime1::monitorexit_nofpu_id), relocInfo::runtime_call_type); - } - - __ delayed()->mov_or_nop(_lock_reg->as_register(), G4); - __ br(Assembler::always, true, Assembler::pt, _continuation); - __ delayed()->nop(); -} - -// 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 (especially 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* ) { - // patch sites on sparc are always properly aligned. -} - -void PatchingStub::emit_code(LIR_Assembler* ce) { - // copy original code here - assert(NativeCall::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF, - "not enough room for call"); - assert((_bytes_to_copy & 0x3) == 0, "must copy a multiple of four bytes"); - - Label call_patch; - - int being_initialized_entry = __ offset(); - - if (_id == load_klass_id) { - // produce a copy of the load klass instruction for use by the being initialized case -#ifdef ASSERT - address start = __ pc(); -#endif - AddressLiteral addrlit(NULL, metadata_Relocation::spec(_index)); - __ patchable_set(addrlit, _obj); - -#ifdef ASSERT - for (int i = 0; i < _bytes_to_copy; i++) { - address ptr = (address)(_pc_start + i); - int a_byte = (*ptr) & 0xFF; - assert(a_byte == *start++, "should be the same code"); - } -#endif - } else if (_id == load_mirror_id || _id == load_appendix_id) { - // produce a copy of the load mirror instruction for use by the being initialized case -#ifdef ASSERT - address start = __ pc(); -#endif - AddressLiteral addrlit(NULL, oop_Relocation::spec(_index)); - __ patchable_set(addrlit, _obj); - -#ifdef ASSERT - for (int i = 0; i < _bytes_to_copy; i++) { - address ptr = (address)(_pc_start + i); - int a_byte = (*ptr) & 0xFF; - assert(a_byte == *start++, "should be the same code"); - } -#endif - } else { - // make a copy the code which is going to be patched. - for (int i = 0; i < _bytes_to_copy; i++) { - address ptr = (address)(_pc_start + i); - int a_byte = (*ptr) & 0xFF; - __ emit_int8 (a_byte); - } - } - - address end_of_patch = __ pc(); - int bytes_to_skip = 0; - if (_id == load_mirror_id) { - int offset = __ offset(); - if (CommentedAssembly) { - __ block_comment(" being_initialized check"); - } - - // static field accesses have special semantics while the class - // initializer is being run so we emit a test which can be used to - // check that this code is being executed by the initializing - // thread. - assert(_obj != noreg, "must be a valid register"); - assert(_index >= 0, "must have oop index"); - __ ld_ptr(_obj, java_lang_Class::klass_offset_in_bytes(), G3); - __ ld_ptr(G3, in_bytes(InstanceKlass::init_thread_offset()), G3); - __ cmp_and_brx_short(G2_thread, G3, Assembler::notEqual, Assembler::pn, call_patch); - - // load_klass patches may execute the patched code before it's - // copied back into place so we need to jump back into the main - // code of the nmethod to continue execution. - __ br(Assembler::always, false, Assembler::pt, _patch_site_continuation); - __ delayed()->nop(); - - // make sure this extra code gets skipped - bytes_to_skip += __ offset() - offset; - } - - // Now emit the patch record telling the runtime how to find the - // pieces of the patch. We only need 3 bytes but it has to be - // aligned as an instruction so emit 4 bytes. - int sizeof_patch_record = 4; - bytes_to_skip += sizeof_patch_record; - - // emit the offsets needed to find the code to patch - int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record; - - // Emit the patch record. We need to emit a full word, so emit an extra empty byte - __ emit_int8(0); - __ emit_int8(being_initialized_entry_offset); - __ emit_int8(bytes_to_skip); - __ emit_int8(_bytes_to_copy); - address patch_info_pc = __ pc(); - assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); - - address entry = __ pc(); - NativeGeneralJump::insert_unconditional((address)_pc_start, entry); - address target = NULL; - relocInfo::relocType reloc_type = relocInfo::none; - switch (_id) { - case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break; - case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); reloc_type = relocInfo::metadata_type; break; - case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); reloc_type = relocInfo::oop_type; break; - case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); reloc_type = relocInfo::oop_type; break; - default: ShouldNotReachHere(); - } - __ bind(call_patch); - - if (CommentedAssembly) { - __ block_comment("patch entry point"); - } - __ call(target, relocInfo::runtime_call_type); - __ delayed()->nop(); - assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change"); - ce->add_call_info_here(_info); - __ br(Assembler::always, false, Assembler::pt, _patch_site_entry); - __ delayed()->nop(); - if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) { - CodeSection* cs = __ code_section(); - address pc = (address)_pc_start; - RelocIterator iter(cs, pc, pc + 1); - relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none); - - pc = (address)(_pc_start + NativeMovConstReg::add_offset); - RelocIterator iter2(cs, pc, pc+1); - relocInfo::change_reloc_info_for_address(&iter2, (address) pc, reloc_type, relocInfo::none); - } - -} - - -void DeoptimizeStub::emit_code(LIR_Assembler* ce) { - __ bind(_entry); - __ set(_trap_request, G4); - __ call(Runtime1::entry_for(Runtime1::deoptimize_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - 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); - __ mov(src()->as_register(), O0); - __ mov(src_pos()->as_register(), O1); - __ mov(dst()->as_register(), O2); - __ mov(dst_pos()->as_register(), O3); - __ mov(length()->as_register(), O4); - - ce->emit_static_call_stub(); - if (ce->compilation()->bailed_out()) { - return; // CodeCache is full - } - - __ call(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type); - __ delayed()->nop(); - ce->add_call_info_here(info()); - ce->verify_oop_map(info()); - -#ifndef PRODUCT - __ set((intptr_t)&Runtime1::_arraycopy_slowcase_cnt, O0); - __ ld(O0, 0, O1); - __ inc(O1); - __ st(O1, 0, O0); -#endif - - __ br(Assembler::always, false, Assembler::pt, _continuation); - __ delayed()->nop(); -} - -#undef __ diff --git a/src/hotspot/cpu/sparc/c1_Defs_sparc.hpp b/src/hotspot/cpu/sparc/c1_Defs_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_Defs_sparc.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_DEFS_SPARC_HPP -#define CPU_SPARC_C1_DEFS_SPARC_HPP - -// native word offsets from memory address (big endian) -enum { - pd_lo_word_offset_in_bytes = BytesPerInt, - pd_hi_word_offset_in_bytes = 0 -}; - - -// explicit rounding operations are not required to implement the strictFP mode -enum { - pd_strict_fp_requires_explicit_rounding = false -}; - - -// registers -enum { - pd_nof_cpu_regs_frame_map = 32, // number of registers used during code emission - pd_nof_caller_save_cpu_regs_frame_map = 10, // number of cpu registers killed by calls - pd_nof_cpu_regs_reg_alloc = 20, // number of registers that are visible to register allocator - pd_nof_cpu_regs_linearscan = 32,// number of registers visible linear scan - pd_first_cpu_reg = 0, - pd_last_cpu_reg = 31, - pd_last_allocatable_cpu_reg = 19, - pd_first_callee_saved_reg = 0, - pd_last_callee_saved_reg = 13, - - pd_nof_fpu_regs_frame_map = 32, // number of registers used during code emission - pd_nof_caller_save_fpu_regs_frame_map = 32, // number of fpu registers killed by calls - pd_nof_fpu_regs_reg_alloc = 32, // number of registers that are visible to register allocator - pd_nof_fpu_regs_linearscan = 32, // number of registers visible to linear scan - pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, - pd_last_fpu_reg = pd_nof_cpu_regs_frame_map + pd_nof_fpu_regs_frame_map - 1, - - pd_nof_xmm_regs_linearscan = 0, - pd_nof_caller_save_xmm_regs = 0, - pd_first_xmm_reg = -1, - pd_last_xmm_reg = -1 -}; - - -// for debug info: a float value in a register is saved in single precision by runtime stubs -enum { - pd_float_saved_as_double = false -}; - -#endif // CPU_SPARC_C1_DEFS_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.cpp b/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2005, 2017, 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. - * - */ - -// No FPU stack on SPARC diff --git a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.hpp b/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_FpuStackSim_sparc.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2005, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_FPUSTACKSIM_SPARC_HPP -#define CPU_SPARC_C1_FPUSTACKSIM_SPARC_HPP - -// No FPU stack on SPARC -class FpuStackSim; - -#endif // CPU_SPARC_C1_FPUSTACKSIM_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.cpp b/src/hotspot/cpu/sparc/c1_FrameMap_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "c1/c1_FrameMap.hpp" -#include "c1/c1_LIR.hpp" -#include "runtime/sharedRuntime.hpp" -#include "vmreg_sparc.inline.hpp" - - -const int FrameMap::pd_c_runtime_reserved_arg_size = 7; - - -LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) { - 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 + STACK_BIAS, type)); - } else if (r_1->is_Register()) { - Register reg = r_1->as_Register(); - if (outgoing) { - assert(!reg->is_in(), "should be using I regs"); - } else { - assert(!reg->is_out(), "should be using O regs"); - } - if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { - opr = as_long_opr(reg); - } else if (is_reference_type(type)) { - opr = as_oop_opr(reg); - } else if (type == T_METADATA) { - opr = as_metadata_opr(reg); - } else if (type == T_ADDRESS) { - opr = as_address_opr(reg); - } else { - opr = as_opr(reg); - } - } else if (r_1->is_FloatRegister()) { - assert(type == T_DOUBLE || type == T_FLOAT, "wrong type"); - FloatRegister f = r_1->as_FloatRegister(); - if (type == T_DOUBLE) { - opr = as_double_opr(f); - } else { - opr = as_float_opr(f); - } - } - return opr; -} - -// FrameMap -//-------------------------------------------------------- - -FloatRegister FrameMap::_fpu_regs [FrameMap::nof_fpu_regs]; - -// some useful constant RInfo's: -LIR_Opr FrameMap::in_long_opr; -LIR_Opr FrameMap::out_long_opr; -LIR_Opr FrameMap::g1_long_single_opr; - -LIR_Opr FrameMap::F0_opr; -LIR_Opr FrameMap::F0_double_opr; - -LIR_Opr FrameMap::G0_opr; -LIR_Opr FrameMap::G1_opr; -LIR_Opr FrameMap::G2_opr; -LIR_Opr FrameMap::G3_opr; -LIR_Opr FrameMap::G4_opr; -LIR_Opr FrameMap::G5_opr; -LIR_Opr FrameMap::G6_opr; -LIR_Opr FrameMap::G7_opr; -LIR_Opr FrameMap::O0_opr; -LIR_Opr FrameMap::O1_opr; -LIR_Opr FrameMap::O2_opr; -LIR_Opr FrameMap::O3_opr; -LIR_Opr FrameMap::O4_opr; -LIR_Opr FrameMap::O5_opr; -LIR_Opr FrameMap::O6_opr; -LIR_Opr FrameMap::O7_opr; -LIR_Opr FrameMap::L0_opr; -LIR_Opr FrameMap::L1_opr; -LIR_Opr FrameMap::L2_opr; -LIR_Opr FrameMap::L3_opr; -LIR_Opr FrameMap::L4_opr; -LIR_Opr FrameMap::L5_opr; -LIR_Opr FrameMap::L6_opr; -LIR_Opr FrameMap::L7_opr; -LIR_Opr FrameMap::I0_opr; -LIR_Opr FrameMap::I1_opr; -LIR_Opr FrameMap::I2_opr; -LIR_Opr FrameMap::I3_opr; -LIR_Opr FrameMap::I4_opr; -LIR_Opr FrameMap::I5_opr; -LIR_Opr FrameMap::I6_opr; -LIR_Opr FrameMap::I7_opr; - -LIR_Opr FrameMap::G0_oop_opr; -LIR_Opr FrameMap::G1_oop_opr; -LIR_Opr FrameMap::G2_oop_opr; -LIR_Opr FrameMap::G3_oop_opr; -LIR_Opr FrameMap::G4_oop_opr; -LIR_Opr FrameMap::G5_oop_opr; -LIR_Opr FrameMap::G6_oop_opr; -LIR_Opr FrameMap::G7_oop_opr; -LIR_Opr FrameMap::O0_oop_opr; -LIR_Opr FrameMap::O1_oop_opr; -LIR_Opr FrameMap::O2_oop_opr; -LIR_Opr FrameMap::O3_oop_opr; -LIR_Opr FrameMap::O4_oop_opr; -LIR_Opr FrameMap::O5_oop_opr; -LIR_Opr FrameMap::O6_oop_opr; -LIR_Opr FrameMap::O7_oop_opr; -LIR_Opr FrameMap::L0_oop_opr; -LIR_Opr FrameMap::L1_oop_opr; -LIR_Opr FrameMap::L2_oop_opr; -LIR_Opr FrameMap::L3_oop_opr; -LIR_Opr FrameMap::L4_oop_opr; -LIR_Opr FrameMap::L5_oop_opr; -LIR_Opr FrameMap::L6_oop_opr; -LIR_Opr FrameMap::L7_oop_opr; -LIR_Opr FrameMap::I0_oop_opr; -LIR_Opr FrameMap::I1_oop_opr; -LIR_Opr FrameMap::I2_oop_opr; -LIR_Opr FrameMap::I3_oop_opr; -LIR_Opr FrameMap::I4_oop_opr; -LIR_Opr FrameMap::I5_oop_opr; -LIR_Opr FrameMap::I6_oop_opr; -LIR_Opr FrameMap::I7_oop_opr; - -LIR_Opr FrameMap::G0_metadata_opr; -LIR_Opr FrameMap::G1_metadata_opr; -LIR_Opr FrameMap::G2_metadata_opr; -LIR_Opr FrameMap::G3_metadata_opr; -LIR_Opr FrameMap::G4_metadata_opr; -LIR_Opr FrameMap::G5_metadata_opr; -LIR_Opr FrameMap::G6_metadata_opr; -LIR_Opr FrameMap::G7_metadata_opr; -LIR_Opr FrameMap::O0_metadata_opr; -LIR_Opr FrameMap::O1_metadata_opr; -LIR_Opr FrameMap::O2_metadata_opr; -LIR_Opr FrameMap::O3_metadata_opr; -LIR_Opr FrameMap::O4_metadata_opr; -LIR_Opr FrameMap::O5_metadata_opr; -LIR_Opr FrameMap::O6_metadata_opr; -LIR_Opr FrameMap::O7_metadata_opr; -LIR_Opr FrameMap::L0_metadata_opr; -LIR_Opr FrameMap::L1_metadata_opr; -LIR_Opr FrameMap::L2_metadata_opr; -LIR_Opr FrameMap::L3_metadata_opr; -LIR_Opr FrameMap::L4_metadata_opr; -LIR_Opr FrameMap::L5_metadata_opr; -LIR_Opr FrameMap::L6_metadata_opr; -LIR_Opr FrameMap::L7_metadata_opr; -LIR_Opr FrameMap::I0_metadata_opr; -LIR_Opr FrameMap::I1_metadata_opr; -LIR_Opr FrameMap::I2_metadata_opr; -LIR_Opr FrameMap::I3_metadata_opr; -LIR_Opr FrameMap::I4_metadata_opr; -LIR_Opr FrameMap::I5_metadata_opr; -LIR_Opr FrameMap::I6_metadata_opr; -LIR_Opr FrameMap::I7_metadata_opr; - -LIR_Opr FrameMap::SP_opr; -LIR_Opr FrameMap::FP_opr; - -LIR_Opr FrameMap::Oexception_opr; -LIR_Opr FrameMap::Oissuing_pc_opr; - -LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, }; -LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, }; - - -FloatRegister FrameMap::nr2floatreg (int rnr) { - assert(_init_done, "tables not initialized"); - debug_only(fpu_range_check(rnr);) - return _fpu_regs[rnr]; -} - - -// returns true if reg could be smashed by a callee. -bool FrameMap::is_caller_save_register (LIR_Opr reg) { - if (reg->is_single_fpu() || reg->is_double_fpu()) { return true; } - if (reg->is_double_cpu()) { - return is_caller_save_register(reg->as_register_lo()) || - is_caller_save_register(reg->as_register_hi()); - } - return is_caller_save_register(reg->as_register()); -} - - -NEEDS_CLEANUP // once the new calling convention is enabled, we no - // longer need to treat I5, I4 and L0 specially -// Because the interpreter destroys caller's I5, I4 and L0, -// we must spill them before doing a Java call as we may land in -// interpreter. -bool FrameMap::is_caller_save_register (Register r) { - return (r->is_global() && (r != G0)) || r->is_out(); -} - - -void FrameMap::initialize() { - assert(!_init_done, "once"); - - int i=0; - // Register usage: - // O6: sp - // I6: fp - // I7: return address - // G0: zero - // G2: thread - // G7: not available - // G6: not available - /* 0 */ map_register(i++, L0); - /* 1 */ map_register(i++, L1); - /* 2 */ map_register(i++, L2); - /* 3 */ map_register(i++, L3); - /* 4 */ map_register(i++, L4); - /* 5 */ map_register(i++, L5); - /* 6 */ map_register(i++, L6); - /* 7 */ map_register(i++, L7); - - /* 8 */ map_register(i++, I0); - /* 9 */ map_register(i++, I1); - /* 10 */ map_register(i++, I2); - /* 11 */ map_register(i++, I3); - /* 12 */ map_register(i++, I4); - /* 13 */ map_register(i++, I5); - /* 14 */ map_register(i++, O0); - /* 15 */ map_register(i++, O1); - /* 16 */ map_register(i++, O2); - /* 17 */ map_register(i++, O3); - /* 18 */ map_register(i++, O4); - /* 19 */ map_register(i++, O5); // <- last register visible in RegAlloc (RegAlloc::nof+cpu_regs) - /* 20 */ map_register(i++, G1); - /* 21 */ map_register(i++, G3); - /* 22 */ map_register(i++, G4); - /* 23 */ map_register(i++, G5); - /* 24 */ map_register(i++, G0); - - // the following registers are not normally available - /* 25 */ map_register(i++, O7); - /* 26 */ map_register(i++, G2); - /* 27 */ map_register(i++, O6); - /* 28 */ map_register(i++, I6); - /* 29 */ map_register(i++, I7); - /* 30 */ map_register(i++, G6); - /* 31 */ map_register(i++, G7); - assert(i == nof_cpu_regs, "number of CPU registers"); - - for (i = 0; i < nof_fpu_regs; i++) { - _fpu_regs[i] = as_FloatRegister(i); - } - - _init_done = true; - - in_long_opr = as_long_opr(I0); - out_long_opr = as_long_opr(O0); - g1_long_single_opr = as_long_single_opr(G1); - - G0_opr = as_opr(G0); - G1_opr = as_opr(G1); - G2_opr = as_opr(G2); - G3_opr = as_opr(G3); - G4_opr = as_opr(G4); - G5_opr = as_opr(G5); - G6_opr = as_opr(G6); - G7_opr = as_opr(G7); - O0_opr = as_opr(O0); - O1_opr = as_opr(O1); - O2_opr = as_opr(O2); - O3_opr = as_opr(O3); - O4_opr = as_opr(O4); - O5_opr = as_opr(O5); - O6_opr = as_opr(O6); - O7_opr = as_opr(O7); - L0_opr = as_opr(L0); - L1_opr = as_opr(L1); - L2_opr = as_opr(L2); - L3_opr = as_opr(L3); - L4_opr = as_opr(L4); - L5_opr = as_opr(L5); - L6_opr = as_opr(L6); - L7_opr = as_opr(L7); - I0_opr = as_opr(I0); - I1_opr = as_opr(I1); - I2_opr = as_opr(I2); - I3_opr = as_opr(I3); - I4_opr = as_opr(I4); - I5_opr = as_opr(I5); - I6_opr = as_opr(I6); - I7_opr = as_opr(I7); - - G0_oop_opr = as_oop_opr(G0); - G1_oop_opr = as_oop_opr(G1); - G2_oop_opr = as_oop_opr(G2); - G3_oop_opr = as_oop_opr(G3); - G4_oop_opr = as_oop_opr(G4); - G5_oop_opr = as_oop_opr(G5); - G6_oop_opr = as_oop_opr(G6); - G7_oop_opr = as_oop_opr(G7); - O0_oop_opr = as_oop_opr(O0); - O1_oop_opr = as_oop_opr(O1); - O2_oop_opr = as_oop_opr(O2); - O3_oop_opr = as_oop_opr(O3); - O4_oop_opr = as_oop_opr(O4); - O5_oop_opr = as_oop_opr(O5); - O6_oop_opr = as_oop_opr(O6); - O7_oop_opr = as_oop_opr(O7); - L0_oop_opr = as_oop_opr(L0); - L1_oop_opr = as_oop_opr(L1); - L2_oop_opr = as_oop_opr(L2); - L3_oop_opr = as_oop_opr(L3); - L4_oop_opr = as_oop_opr(L4); - L5_oop_opr = as_oop_opr(L5); - L6_oop_opr = as_oop_opr(L6); - L7_oop_opr = as_oop_opr(L7); - I0_oop_opr = as_oop_opr(I0); - I1_oop_opr = as_oop_opr(I1); - I2_oop_opr = as_oop_opr(I2); - I3_oop_opr = as_oop_opr(I3); - I4_oop_opr = as_oop_opr(I4); - I5_oop_opr = as_oop_opr(I5); - I6_oop_opr = as_oop_opr(I6); - I7_oop_opr = as_oop_opr(I7); - - G0_metadata_opr = as_metadata_opr(G0); - G1_metadata_opr = as_metadata_opr(G1); - G2_metadata_opr = as_metadata_opr(G2); - G3_metadata_opr = as_metadata_opr(G3); - G4_metadata_opr = as_metadata_opr(G4); - G5_metadata_opr = as_metadata_opr(G5); - G6_metadata_opr = as_metadata_opr(G6); - G7_metadata_opr = as_metadata_opr(G7); - O0_metadata_opr = as_metadata_opr(O0); - O1_metadata_opr = as_metadata_opr(O1); - O2_metadata_opr = as_metadata_opr(O2); - O3_metadata_opr = as_metadata_opr(O3); - O4_metadata_opr = as_metadata_opr(O4); - O5_metadata_opr = as_metadata_opr(O5); - O6_metadata_opr = as_metadata_opr(O6); - O7_metadata_opr = as_metadata_opr(O7); - L0_metadata_opr = as_metadata_opr(L0); - L1_metadata_opr = as_metadata_opr(L1); - L2_metadata_opr = as_metadata_opr(L2); - L3_metadata_opr = as_metadata_opr(L3); - L4_metadata_opr = as_metadata_opr(L4); - L5_metadata_opr = as_metadata_opr(L5); - L6_metadata_opr = as_metadata_opr(L6); - L7_metadata_opr = as_metadata_opr(L7); - I0_metadata_opr = as_metadata_opr(I0); - I1_metadata_opr = as_metadata_opr(I1); - I2_metadata_opr = as_metadata_opr(I2); - I3_metadata_opr = as_metadata_opr(I3); - I4_metadata_opr = as_metadata_opr(I4); - I5_metadata_opr = as_metadata_opr(I5); - I6_metadata_opr = as_metadata_opr(I6); - I7_metadata_opr = as_metadata_opr(I7); - - FP_opr = as_pointer_opr(FP); - SP_opr = as_pointer_opr(SP); - - F0_opr = as_float_opr(F0); - F0_double_opr = as_double_opr(F0); - - Oexception_opr = as_oop_opr(Oexception); - Oissuing_pc_opr = as_opr(Oissuing_pc); - - _caller_save_cpu_regs[0] = FrameMap::O0_opr; - _caller_save_cpu_regs[1] = FrameMap::O1_opr; - _caller_save_cpu_regs[2] = FrameMap::O2_opr; - _caller_save_cpu_regs[3] = FrameMap::O3_opr; - _caller_save_cpu_regs[4] = FrameMap::O4_opr; - _caller_save_cpu_regs[5] = FrameMap::O5_opr; - _caller_save_cpu_regs[6] = FrameMap::G1_opr; - _caller_save_cpu_regs[7] = FrameMap::G3_opr; - _caller_save_cpu_regs[8] = FrameMap::G4_opr; - _caller_save_cpu_regs[9] = FrameMap::G5_opr; - 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 { - return Address(SP, STACK_BIAS + in_bytes(sp_offset)); -} - - -VMReg FrameMap::fpu_regname (int n) { - return as_FloatRegister(n)->as_VMReg(); -} - - -LIR_Opr FrameMap::stack_pointer() { - return SP_opr; -} - - -// JSR 292 -LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { - assert(L7 == L7_mh_SP_save, "must be same register"); - return L7_opr; -} - - -bool FrameMap::validate_frame() { - int max_offset = in_bytes(framesize_in_bytes()); - int java_index = 0; - for (int i = 0; i < _incoming_arguments->length(); i++) { - LIR_Opr opr = _incoming_arguments->at(i); - if (opr->is_stack()) { - max_offset = MAX2(_argument_locations->at(java_index), max_offset); - } - java_index += type2size[opr->type()]; - } - return Assembler::is_simm13(max_offset + STACK_BIAS); -} diff --git a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.hpp b/src/hotspot/cpu/sparc/c1_FrameMap_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_FrameMap_sparc.hpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_FRAMEMAP_SPARC_HPP -#define CPU_SPARC_C1_FRAMEMAP_SPARC_HPP - - public: - - enum { - nof_reg_args = 6, // registers o0-o5 are available for parameter passing - first_available_sp_in_frame = frame::memory_parameter_word_sp_offset * BytesPerWord, - frame_pad_in_bytes = 0 - }; - - static const int pd_c_runtime_reserved_arg_size; - - static LIR_Opr G0_opr; - static LIR_Opr G1_opr; - static LIR_Opr G2_opr; - static LIR_Opr G3_opr; - static LIR_Opr G4_opr; - static LIR_Opr G5_opr; - static LIR_Opr G6_opr; - static LIR_Opr G7_opr; - static LIR_Opr O0_opr; - static LIR_Opr O1_opr; - static LIR_Opr O2_opr; - static LIR_Opr O3_opr; - static LIR_Opr O4_opr; - static LIR_Opr O5_opr; - static LIR_Opr O6_opr; - static LIR_Opr O7_opr; - static LIR_Opr L0_opr; - static LIR_Opr L1_opr; - static LIR_Opr L2_opr; - static LIR_Opr L3_opr; - static LIR_Opr L4_opr; - static LIR_Opr L5_opr; - static LIR_Opr L6_opr; - static LIR_Opr L7_opr; - static LIR_Opr I0_opr; - static LIR_Opr I1_opr; - static LIR_Opr I2_opr; - static LIR_Opr I3_opr; - static LIR_Opr I4_opr; - static LIR_Opr I5_opr; - static LIR_Opr I6_opr; - static LIR_Opr I7_opr; - - static LIR_Opr SP_opr; - static LIR_Opr FP_opr; - - static LIR_Opr G0_oop_opr; - static LIR_Opr G1_oop_opr; - static LIR_Opr G2_oop_opr; - static LIR_Opr G3_oop_opr; - static LIR_Opr G4_oop_opr; - static LIR_Opr G5_oop_opr; - static LIR_Opr G6_oop_opr; - static LIR_Opr G7_oop_opr; - static LIR_Opr O0_oop_opr; - static LIR_Opr O1_oop_opr; - static LIR_Opr O2_oop_opr; - static LIR_Opr O3_oop_opr; - static LIR_Opr O4_oop_opr; - static LIR_Opr O5_oop_opr; - static LIR_Opr O6_oop_opr; - static LIR_Opr O7_oop_opr; - static LIR_Opr L0_oop_opr; - static LIR_Opr L1_oop_opr; - static LIR_Opr L2_oop_opr; - static LIR_Opr L3_oop_opr; - static LIR_Opr L4_oop_opr; - static LIR_Opr L5_oop_opr; - static LIR_Opr L6_oop_opr; - static LIR_Opr L7_oop_opr; - static LIR_Opr I0_oop_opr; - static LIR_Opr I1_oop_opr; - static LIR_Opr I2_oop_opr; - static LIR_Opr I3_oop_opr; - static LIR_Opr I4_oop_opr; - static LIR_Opr I5_oop_opr; - static LIR_Opr I6_oop_opr; - static LIR_Opr I7_oop_opr; - - static LIR_Opr G0_metadata_opr; - static LIR_Opr G1_metadata_opr; - static LIR_Opr G2_metadata_opr; - static LIR_Opr G3_metadata_opr; - static LIR_Opr G4_metadata_opr; - static LIR_Opr G5_metadata_opr; - static LIR_Opr G6_metadata_opr; - static LIR_Opr G7_metadata_opr; - static LIR_Opr O0_metadata_opr; - static LIR_Opr O1_metadata_opr; - static LIR_Opr O2_metadata_opr; - static LIR_Opr O3_metadata_opr; - static LIR_Opr O4_metadata_opr; - static LIR_Opr O5_metadata_opr; - static LIR_Opr O6_metadata_opr; - static LIR_Opr O7_metadata_opr; - static LIR_Opr L0_metadata_opr; - static LIR_Opr L1_metadata_opr; - static LIR_Opr L2_metadata_opr; - static LIR_Opr L3_metadata_opr; - static LIR_Opr L4_metadata_opr; - static LIR_Opr L5_metadata_opr; - static LIR_Opr L6_metadata_opr; - static LIR_Opr L7_metadata_opr; - static LIR_Opr I0_metadata_opr; - static LIR_Opr I1_metadata_opr; - static LIR_Opr I2_metadata_opr; - static LIR_Opr I3_metadata_opr; - static LIR_Opr I4_metadata_opr; - static LIR_Opr I5_metadata_opr; - static LIR_Opr I6_metadata_opr; - static LIR_Opr I7_metadata_opr; - - static LIR_Opr in_long_opr; - static LIR_Opr out_long_opr; - static LIR_Opr g1_long_single_opr; - - static LIR_Opr F0_opr; - static LIR_Opr F0_double_opr; - - static LIR_Opr Oexception_opr; - static LIR_Opr Oissuing_pc_opr; - - private: - static FloatRegister _fpu_regs [nof_fpu_regs]; - - static LIR_Opr as_long_single_opr(Register r) { - return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); - } - static LIR_Opr as_long_pair_opr(Register r) { - return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r)); - } - - public: - - static LIR_Opr as_long_opr(Register r) { - return as_long_single_opr(r); - } - static LIR_Opr as_pointer_opr(Register r) { - return as_long_single_opr(r); - } - static LIR_Opr as_float_opr(FloatRegister r) { - return LIR_OprFact::single_fpu(r->encoding()); - } - static LIR_Opr as_double_opr(FloatRegister r) { - return LIR_OprFact::double_fpu(r->successor()->encoding(), r->encoding()); - } - - static FloatRegister nr2floatreg (int rnr); - - static VMReg fpu_regname (int n); - - static bool is_caller_save_register (LIR_Opr reg); - static bool is_caller_save_register (Register r); - - 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; } - -#endif // CPU_SPARC_C1_FRAMEMAP_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp +++ /dev/null @@ -1,3358 +0,0 @@ -/* - * Copyright (c) 2000, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "c1/c1_Compilation.hpp" -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "c1/c1_Runtime1.hpp" -#include "c1/c1_ValueStack.hpp" -#include "ci/ciArrayKlass.hpp" -#include "ci/ciInstance.hpp" -#include "gc/shared/collectedHeap.hpp" -#include "memory/universe.hpp" -#include "nativeInst_sparc.hpp" -#include "oops/objArrayKlass.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/jniHandles.inline.hpp" -#include "runtime/safepointMechanism.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/powerOfTwo.hpp" - -#define __ _masm-> - - -//------------------------------------------------------------ - - -bool LIR_Assembler::is_small_constant(LIR_Opr opr) { - if (opr->is_constant()) { - LIR_Const* constant = opr->as_constant_ptr(); - switch (constant->type()) { - case T_INT: { - jint value = constant->as_jint(); - return Assembler::is_simm13(value); - } - - default: - return false; - } - } - return false; -} - - -bool LIR_Assembler::is_single_instruction(LIR_Op* op) { - switch (op->code()) { - case lir_null_check: - return true; - - - case lir_add: - case lir_ushr: - case lir_shr: - case lir_shl: - // integer shifts and adds are always one instruction - return op->result_opr()->is_single_cpu(); - - - case lir_move: { - LIR_Op1* op1 = op->as_Op1(); - LIR_Opr src = op1->in_opr(); - LIR_Opr dst = op1->result_opr(); - - if (src == dst) { - NEEDS_CLEANUP; - // this works around a problem where moves with the same src and dst - // end up in the delay slot and then the assembler swallows the mov - // since it has no effect and then it complains because the delay slot - // is empty. returning false stops the optimizer from putting this in - // the delay slot - return false; - } - - // don't put moves involving oops into the delay slot since the VerifyOops code - // will make it much larger than a single instruction. - if (VerifyOops) { - return false; - } - - if (src->is_double_cpu() || dst->is_double_cpu() || op1->patch_code() != lir_patch_none || - ((src->is_double_fpu() || dst->is_double_fpu()) && op1->move_kind() != lir_move_normal)) { - return false; - } - - if (UseCompressedOops) { - if (dst->is_address() && !dst->is_stack() && is_reference_type(dst->type())) return false; - if (src->is_address() && !src->is_stack() && is_reference_type(src->type())) return false; - } - - if (UseCompressedClassPointers) { - if (src->is_address() && !src->is_stack() && src->type() == T_ADDRESS && - src->as_address_ptr()->disp() == oopDesc::klass_offset_in_bytes()) return false; - } - - if (dst->is_register()) { - if (src->is_address() && Assembler::is_simm13(src->as_address_ptr()->disp())) { - return !PatchALot; - } else if (src->is_single_stack()) { - return true; - } - } - - if (src->is_register()) { - if (dst->is_address() && Assembler::is_simm13(dst->as_address_ptr()->disp())) { - return !PatchALot; - } else if (dst->is_single_stack()) { - return true; - } - } - - if (dst->is_register() && - ((src->is_register() && src->is_single_word() && src->is_same_type(dst)) || - (src->is_constant() && LIR_Assembler::is_small_constant(op->as_Op1()->in_opr())))) { - return true; - } - - return false; - } - - default: - return false; - } - ShouldNotReachHere(); -} - - -LIR_Opr LIR_Assembler::receiverOpr() { - return FrameMap::O0_oop_opr; -} - - -LIR_Opr LIR_Assembler::osrBufferPointer() { - return FrameMap::I0_opr; -} - - -int LIR_Assembler::initial_frame_size_in_bytes() const { - return in_bytes(frame_map()->framesize_in_bytes()); -} - - -// inline cache check: the inline cached class is in G5_inline_cache_reg(G5); -// we fetch the class of the receiver (O0) and compare it with the cached class. -// If they do not match we jump to slow case. -int LIR_Assembler::check_icache() { - int offset = __ offset(); - __ inline_cache_check(O0, G5_inline_cache_reg); - return offset; -} - -void LIR_Assembler::clinit_barrier(ciMethod* method) { - ShouldNotReachHere(); // not implemented -} - -void LIR_Assembler::osr_entry() { - // On-stack-replacement entry sequence (interpreter frame layout described in interpreter_sparc.cpp): - // - // 1. Create a new compiled activation. - // 2. Initialize local variables in the compiled activation. The expression stack must be empty - // at the osr_bci; it is not initialized. - // 3. Jump to the continuation address in compiled code to resume execution. - - // OSR entry point - offsets()->set_value(CodeOffsets::OSR_Entry, code_offset()); - BlockBegin* osr_entry = compilation()->hir()->osr_entry(); - ValueStack* entry_state = osr_entry->end()->state(); - int number_of_locks = entry_state->locks_size(); - - // Create a frame for the compiled activation. - __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); - - // OSR buffer is - // - // locals[nlocals-1..0] - // monitors[number_of_locks-1..0] - // - // locals is a direct copy of the interpreter frame so in the osr buffer - // so first slot in the local array is the last local from the interpreter - // and last slot is local[0] (receiver) from the interpreter - // - // Similarly with locks. The first lock slot in the osr buffer is the nth lock - // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock - // in the interpreter frame (the method lock if a sync method) - - // Initialize monitors in the compiled activation. - // I0: pointer to osr buffer - // - // All other registers are dead at this point and the locals will be - // copied into place by code emitted in the IR. - - Register OSR_buf = osrBufferPointer()->as_register(); - { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); - int monitor_offset = BytesPerWord * method()->max_locals() + - (2 * BytesPerWord) * (number_of_locks - 1); - // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in - // the OSR buffer using 2 word entries: first the lock and then - // the oop. - for (int i = 0; i < number_of_locks; i++) { - int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); -#ifdef ASSERT - // verify the interpreter's monitor has a non-null object - { - Label L; - __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7); - __ cmp_and_br_short(O7, G0, Assembler::notEqual, Assembler::pt, L); - __ stop("locked object is NULL"); - __ bind(L); - } -#endif // ASSERT - // Copy the lock field into the compiled activation. - __ ld_ptr(OSR_buf, slot_offset + 0, O7); - __ st_ptr(O7, frame_map()->address_for_monitor_lock(i)); - __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7); - __ st_ptr(O7, frame_map()->address_for_monitor_object(i)); - } - } -} - - -// -------------------------------------------------------------------------------------------- - -void LIR_Assembler::monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register hdr, int monitor_no) { - if (!GenerateSynchronizationCode) return; - - Register obj_reg = obj_opr->as_register(); - Register lock_reg = lock_opr->as_register(); - - Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no); - Register reg = mon_addr.base(); - int offset = mon_addr.disp(); - // compute pointer to BasicLock - if (mon_addr.is_simm13()) { - __ add(reg, offset, lock_reg); - } - else { - __ set(offset, lock_reg); - __ add(reg, lock_reg, lock_reg); - } - // unlock object - MonitorAccessStub* slow_case = new MonitorExitStub(lock_opr, UseFastLocking, monitor_no); - // _slow_case_stubs->append(slow_case); - // temporary fix: must be created after exceptionhandler, therefore as call stub - _slow_case_stubs->append(slow_case); - if (UseFastLocking) { - // try inlined fast unlocking first, revert to slow locking if it fails - // note: lock_reg points to the displaced header since the displaced header offset is 0! - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - __ unlock_object(hdr, obj_reg, lock_reg, *slow_case->entry()); - } else { - // always do slow unlocking - // note: the slow unlocking code could be inlined here, however if we use - // slow unlocking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow unlocking code is the same in either case which simplifies - // debugging - __ br(Assembler::always, false, Assembler::pt, *slow_case->entry()); - __ delayed()->nop(); - } - // done - __ bind(*slow_case->continuation()); -} - - -int LIR_Assembler::emit_exception_handler() { - // if the last instruction is a call (typically to do a throw which - // is coming at the end after block reordering) the return address - // must still point into the code area in order to avoid assertion - // failures when searching for the corresponding bci => add a nop - // (was bug 5/14/1999 - gri) - __ nop(); - - // generate code for exception handler - ciMethod* method = compilation()->method(); - - address handler_base = __ start_a_stub(exception_handler_size()); - - if (handler_base == NULL) { - // not enough space left for the handler - bailout("exception handler overflow"); - return -1; - } - - int offset = code_offset(); - - __ call(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ should_not_reach_here(); - guarantee(code_offset() - offset <= exception_handler_size(), "overflow"); - __ end_a_stub(); - - return offset; -} - - -// Emit the code to remove the frame from the stack in the exception -// unwind path. -int LIR_Assembler::emit_unwind_handler() { -#ifndef PRODUCT - if (CommentedAssembly) { - _masm->block_comment("Unwind handler"); - } -#endif - - int offset = code_offset(); - - // Fetch the exception from TLS and clear out exception related thread state - __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), O0); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset())); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_pc_offset())); - - __ bind(_unwind_handler_entry); - __ verify_not_null_oop(O0); - if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { - __ mov(O0, I0); // Preserve the exception - } - - // Preform needed unlocking - MonitorExitStub* stub = NULL; - if (method()->is_synchronized()) { - monitor_address(0, FrameMap::I1_opr); - stub = new MonitorExitStub(FrameMap::I1_opr, true, 0); - __ unlock_object(I3, I2, I1, *stub->entry()); - __ bind(*stub->continuation()); - } - - if (compilation()->env()->dtrace_method_probes()) { - __ mov(G2_thread, O0); - __ save_thread(I1); // need to preserve thread in G2 across - // runtime call - metadata2reg(method()->constant_encoding(), O1); - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ restore_thread(I1); - } - - if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { - __ mov(I0, O0); // Restore the exception - } - - // dispatch to the unwind logic - __ call(Runtime1::entry_for(Runtime1::unwind_exception_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - - // Emit the slow path assembly - if (stub != NULL) { - stub->emit_code(this); - } - - return offset; -} - - -int LIR_Assembler::emit_deopt_handler() { - // if the last instruction is a call (typically to do a throw which - // is coming at the end after block reordering) the return address - // must still point into the code area in order to avoid assertion - // failures when searching for the corresponding bci => add a nop - // (was bug 5/14/1999 - gri) - __ nop(); - - // generate code for deopt handler - ciMethod* method = compilation()->method(); - address handler_base = __ start_a_stub(deopt_handler_size()); - if (handler_base == NULL) { - // not enough space left for the handler - bailout("deopt handler overflow"); - return -1; - } - - int offset = code_offset(); - AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack()); - __ JUMP(deopt_blob, G3_scratch, 0); // sethi;jmp - __ delayed()->nop(); - guarantee(code_offset() - offset <= deopt_handler_size(), "overflow"); - __ end_a_stub(); - - return offset; -} - - -void LIR_Assembler::jobject2reg(jobject o, Register reg) { - if (o == NULL) { - __ set(NULL_WORD, reg); - } else { -#ifdef ASSERT - { - ThreadInVMfromNative tiv(JavaThread::current()); - assert(Universe::heap()->is_in(JNIHandles::resolve(o)), "should be real oop"); - } -#endif - int oop_index = __ oop_recorder()->find_index(o); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - __ set(NULL_WORD, reg, rspec); // Will be set when the nmethod is created - } -} - - -void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) { - // Allocate a new index in table to hold the object once it's been patched - int oop_index = __ oop_recorder()->allocate_oop_index(NULL); - PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index); - - AddressLiteral addrlit(NULL, oop_Relocation::spec(oop_index)); - assert(addrlit.rspec().type() == relocInfo::oop_type, "must be an oop reloc"); - // It may not seem necessary to use a sethi/add pair to load a NULL into dest, but the - // NULL will be dynamically patched later and the patched value may be large. We must - // therefore generate the sethi/add as a placeholders - __ patchable_set(addrlit, reg); - - patching_epilog(patch, lir_patch_normal, reg, info); -} - - -void LIR_Assembler::metadata2reg(Metadata* o, Register reg) { - __ set_metadata_constant(o, reg); -} - -void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) { - // Allocate a new index in table to hold the klass once it's been patched - int index = __ oop_recorder()->allocate_metadata_index(NULL); - PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index); - AddressLiteral addrlit(NULL, metadata_Relocation::spec(index)); - assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc"); - // It may not seem necessary to use a sethi/add pair to load a NULL into dest, but the - // NULL will be dynamically patched later and the patched value may be large. We must - // therefore generate the sethi/add as a placeholders - __ patchable_set(addrlit, reg); - - patching_epilog(patch, lir_patch_normal, reg, info); -} - -void LIR_Assembler::emit_op3(LIR_Op3* op) { - switch (op->code()) { - case lir_idiv: - case lir_irem: // Both idiv & irem are handled after the switch (below). - break; - case lir_fmaf: - __ fmadd(FloatRegisterImpl::S, - op->in_opr1()->as_float_reg(), - op->in_opr2()->as_float_reg(), - op->in_opr3()->as_float_reg(), - op->result_opr()->as_float_reg()); - return; - case lir_fmad: - __ fmadd(FloatRegisterImpl::D, - op->in_opr1()->as_double_reg(), - op->in_opr2()->as_double_reg(), - op->in_opr3()->as_double_reg(), - op->result_opr()->as_double_reg()); - return; - default: - ShouldNotReachHere(); - break; - } - - // Handle idiv & irem: - - Register Rdividend = op->in_opr1()->as_register(); - Register Rdivisor = noreg; - Register Rscratch = op->in_opr3()->as_register(); - Register Rresult = op->result_opr()->as_register(); - int divisor = -1; - - if (op->in_opr2()->is_register()) { - Rdivisor = op->in_opr2()->as_register(); - } else { - divisor = op->in_opr2()->as_constant_ptr()->as_jint(); - assert(Assembler::is_simm13(divisor), "can only handle simm13"); - } - - assert(Rdividend != Rscratch, ""); - assert(Rdivisor != Rscratch, ""); - assert(op->code() == lir_idiv || op->code() == lir_irem, "Must be irem or idiv"); - - if (Rdivisor == noreg && is_power_of_2(divisor)) { - // convert division by a power of two into some shifts and logical operations - if (op->code() == lir_idiv) { - if (divisor == 2) { - __ srl(Rdividend, 31, Rscratch); - } else { - __ sra(Rdividend, 31, Rscratch); - __ and3(Rscratch, divisor - 1, Rscratch); - } - __ add(Rdividend, Rscratch, Rscratch); - __ sra(Rscratch, log2_int(divisor), Rresult); - return; - } else { - if (divisor == 2) { - __ srl(Rdividend, 31, Rscratch); - } else { - __ sra(Rdividend, 31, Rscratch); - __ and3(Rscratch, divisor - 1,Rscratch); - } - __ add(Rdividend, Rscratch, Rscratch); - __ andn(Rscratch, divisor - 1,Rscratch); - __ sub(Rdividend, Rscratch, Rresult); - return; - } - } - - __ sra(Rdividend, 31, Rscratch); - __ wry(Rscratch); - - add_debug_info_for_div0_here(op->info()); - - if (Rdivisor != noreg) { - __ sdivcc(Rdividend, Rdivisor, (op->code() == lir_idiv ? Rresult : Rscratch)); - } else { - assert(Assembler::is_simm13(divisor), "can only handle simm13"); - __ sdivcc(Rdividend, divisor, (op->code() == lir_idiv ? Rresult : Rscratch)); - } - - Label skip; - __ br(Assembler::overflowSet, true, Assembler::pn, skip); - __ delayed()->Assembler::sethi(0x80000000, (op->code() == lir_idiv ? Rresult : Rscratch)); - __ bind(skip); - - if (op->code() == lir_irem) { - if (Rdivisor != noreg) { - __ smul(Rscratch, Rdivisor, Rscratch); - } else { - __ smul(Rscratch, divisor, Rscratch); - } - __ sub(Rdividend, Rscratch, Rresult); - } -} - - -void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { -#ifdef ASSERT - assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label"); - if (op->block() != NULL) _branch_target_blocks.append(op->block()); - if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock()); -#endif - assert(op->info() == NULL, "shouldn't have CodeEmitInfo"); - - if (op->cond() == lir_cond_always) { - __ br(Assembler::always, false, Assembler::pt, *(op->label())); - } else if (op->code() == lir_cond_float_branch) { - assert(op->ublock() != NULL, "must have unordered successor"); - bool is_unordered = (op->ublock() == op->block()); - Assembler::Condition acond; - switch (op->cond()) { - case lir_cond_equal: acond = Assembler::f_equal; break; - case lir_cond_notEqual: acond = Assembler::f_notEqual; break; - case lir_cond_less: acond = (is_unordered ? Assembler::f_unorderedOrLess : Assembler::f_less); break; - case lir_cond_greater: acond = (is_unordered ? Assembler::f_unorderedOrGreater : Assembler::f_greater); break; - case lir_cond_lessEqual: acond = (is_unordered ? Assembler::f_unorderedOrLessOrEqual : Assembler::f_lessOrEqual); break; - case lir_cond_greaterEqual: acond = (is_unordered ? Assembler::f_unorderedOrGreaterOrEqual: Assembler::f_greaterOrEqual); break; - default : ShouldNotReachHere(); - } - __ fb( acond, false, Assembler::pn, *(op->label())); - } else { - assert (op->code() == lir_branch, "just checking"); - - Assembler::Condition acond; - switch (op->cond()) { - case lir_cond_equal: acond = Assembler::equal; break; - case lir_cond_notEqual: acond = Assembler::notEqual; break; - case lir_cond_less: acond = Assembler::less; break; - case lir_cond_lessEqual: acond = Assembler::lessEqual; break; - case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break; - case lir_cond_greater: acond = Assembler::greater; break; - case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break; - case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break; - default: ShouldNotReachHere(); - }; - - // sparc has different condition codes for testing 32-bit - // vs. 64-bit values. We could always test xcc is we could - // guarantee that 32-bit loads always sign extended but that isn't - // true and since sign extension isn't free, it would impose a - // slight cost. - if (op->type() == T_INT) { - __ br(acond, false, Assembler::pn, *(op->label())); - } else - __ brx(acond, false, Assembler::pn, *(op->label())); - } - // The peephole pass fills the delay slot -} - - -void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { - Bytecodes::Code code = op->bytecode(); - LIR_Opr dst = op->result_opr(); - - switch(code) { - case Bytecodes::_i2l: { - Register rlo = dst->as_register_lo(); - Register rhi = dst->as_register_hi(); - Register rval = op->in_opr()->as_register(); - __ sra(rval, 0, rlo); - break; - } - case Bytecodes::_i2d: - case Bytecodes::_i2f: { - bool is_double = (code == Bytecodes::_i2d); - FloatRegister rdst = is_double ? dst->as_double_reg() : dst->as_float_reg(); - FloatRegisterImpl::Width w = is_double ? FloatRegisterImpl::D : FloatRegisterImpl::S; - FloatRegister rsrc = op->in_opr()->as_float_reg(); - if (rsrc != rdst) { - __ fmov(FloatRegisterImpl::S, rsrc, rdst); - } - __ fitof(w, rdst, rdst); - break; - } - case Bytecodes::_f2i:{ - FloatRegister rsrc = op->in_opr()->as_float_reg(); - Address addr = frame_map()->address_for_slot(dst->single_stack_ix()); - Label L; - // result must be 0 if value is NaN; test by comparing value to itself - __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, rsrc, rsrc); - __ fb(Assembler::f_unordered, true, Assembler::pn, L); - __ delayed()->st(G0, addr); // annuled if contents of rsrc is not NaN - __ ftoi(FloatRegisterImpl::S, rsrc, rsrc); - // move integer result from float register to int register - __ stf(FloatRegisterImpl::S, rsrc, addr.base(), addr.disp()); - __ bind (L); - break; - } - case Bytecodes::_l2i: { - Register rlo = op->in_opr()->as_register_lo(); - Register rhi = op->in_opr()->as_register_hi(); - Register rdst = dst->as_register(); - __ sra(rlo, 0, rdst); - break; - } - case Bytecodes::_d2f: - case Bytecodes::_f2d: { - bool is_double = (code == Bytecodes::_f2d); - assert((!is_double && dst->is_single_fpu()) || (is_double && dst->is_double_fpu()), "check"); - LIR_Opr val = op->in_opr(); - FloatRegister rval = (code == Bytecodes::_d2f) ? val->as_double_reg() : val->as_float_reg(); - FloatRegister rdst = is_double ? dst->as_double_reg() : dst->as_float_reg(); - FloatRegisterImpl::Width vw = is_double ? FloatRegisterImpl::S : FloatRegisterImpl::D; - FloatRegisterImpl::Width dw = is_double ? FloatRegisterImpl::D : FloatRegisterImpl::S; - __ ftof(vw, dw, rval, rdst); - break; - } - case Bytecodes::_i2s: - case Bytecodes::_i2b: { - Register rval = op->in_opr()->as_register(); - Register rdst = dst->as_register(); - int shift = (code == Bytecodes::_i2b) ? (BitsPerInt - T_BYTE_aelem_bytes * BitsPerByte) : (BitsPerInt - BitsPerShort); - __ sll (rval, shift, rdst); - __ sra (rdst, shift, rdst); - break; - } - case Bytecodes::_i2c: { - Register rval = op->in_opr()->as_register(); - Register rdst = dst->as_register(); - int shift = BitsPerInt - T_CHAR_aelem_bytes * BitsPerByte; - __ sll (rval, shift, rdst); - __ srl (rdst, shift, rdst); - break; - } - - default: ShouldNotReachHere(); - } -} - - -void LIR_Assembler::align_call(LIR_Code) { - // do nothing since all instructions are word aligned on sparc -} - - -void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { - __ call(op->addr(), rtype); - // The peephole pass fills the delay slot, add_call_info is done in - // LIR_Assembler::emit_delay. -} - - -void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { - __ ic_call(op->addr(), false); - // The peephole pass fills the delay slot, add_call_info is done in - // LIR_Assembler::emit_delay. -} - - -void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { - add_debug_info_for_null_check_here(op->info()); - __ load_klass(O0, G3_scratch); - if (Assembler::is_simm13(op->vtable_offset())) { - __ ld_ptr(G3_scratch, op->vtable_offset(), G5_method); - } else { - // This will generate 2 instructions - __ set(op->vtable_offset(), G5_method); - // ld_ptr, set_hi, set - __ ld_ptr(G3_scratch, G5_method, G5_method); - } - __ ld_ptr(G5_method, Method::from_compiled_offset(), G3_scratch); - __ callr(G3_scratch, G0); - // the peephole pass fills the delay slot -} - -int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) { - int store_offset; - if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) { - assert(base != O7, "destroying register"); - assert(!unaligned, "can't handle this"); - // for offsets larger than a simm13 we setup the offset in O7 - __ set(offset, O7); - store_offset = store(from_reg, base, O7, type, wide); - } else { - if (is_reference_type(type)) { - __ verify_oop(from_reg->as_register()); - } - store_offset = code_offset(); - switch (type) { - case T_BOOLEAN: // fall through - case T_BYTE : __ stb(from_reg->as_register(), base, offset); break; - case T_CHAR : __ sth(from_reg->as_register(), base, offset); break; - case T_SHORT : __ sth(from_reg->as_register(), base, offset); break; - case T_INT : __ stw(from_reg->as_register(), base, offset); break; - case T_LONG : - if (unaligned || PatchALot) { - // Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem) - assert(G3_scratch != base, "can't handle this"); - assert(G3_scratch != from_reg->as_register_lo(), "can't handle this"); - __ srax(from_reg->as_register_lo(), 32, G3_scratch); - __ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes); - __ stw(G3_scratch, base, offset + hi_word_offset_in_bytes); - } else { - __ stx(from_reg->as_register_lo(), base, offset); - } - break; - case T_ADDRESS: - case T_METADATA: - __ st_ptr(from_reg->as_register(), base, offset); - break; - case T_ARRAY : // fall through - case T_OBJECT: - { - if (UseCompressedOops && !wide) { - __ encode_heap_oop(from_reg->as_register(), G3_scratch); - store_offset = code_offset(); - __ stw(G3_scratch, base, offset); - } else { - __ st_ptr(from_reg->as_register(), base, offset); - } - break; - } - - case T_FLOAT : __ stf(FloatRegisterImpl::S, from_reg->as_float_reg(), base, offset); break; - case T_DOUBLE: - { - FloatRegister reg = from_reg->as_double_reg(); - // split unaligned stores - if (unaligned || PatchALot) { - assert(Assembler::is_simm13(offset + 4), "must be"); - __ stf(FloatRegisterImpl::S, reg->successor(), base, offset + 4); - __ stf(FloatRegisterImpl::S, reg, base, offset); - } else { - __ stf(FloatRegisterImpl::D, reg, base, offset); - } - break; - } - default : ShouldNotReachHere(); - } - } - return store_offset; -} - - -int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide) { - if (is_reference_type(type)) { - __ verify_oop(from_reg->as_register()); - } - int store_offset = code_offset(); - switch (type) { - case T_BOOLEAN: // fall through - case T_BYTE : __ stb(from_reg->as_register(), base, disp); break; - case T_CHAR : __ sth(from_reg->as_register(), base, disp); break; - case T_SHORT : __ sth(from_reg->as_register(), base, disp); break; - case T_INT : __ stw(from_reg->as_register(), base, disp); break; - case T_LONG : - __ stx(from_reg->as_register_lo(), base, disp); - break; - case T_ADDRESS: - __ st_ptr(from_reg->as_register(), base, disp); - break; - case T_ARRAY : // fall through - case T_OBJECT: - { - if (UseCompressedOops && !wide) { - __ encode_heap_oop(from_reg->as_register(), G3_scratch); - store_offset = code_offset(); - __ stw(G3_scratch, base, disp); - } else { - __ st_ptr(from_reg->as_register(), base, disp); - } - break; - } - case T_FLOAT : __ stf(FloatRegisterImpl::S, from_reg->as_float_reg(), base, disp); break; - case T_DOUBLE: __ stf(FloatRegisterImpl::D, from_reg->as_double_reg(), base, disp); break; - default : ShouldNotReachHere(); - } - return store_offset; -} - - -int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned) { - int load_offset; - if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) { - assert(base != O7, "destroying register"); - assert(!unaligned, "can't handle this"); - // for offsets larger than a simm13 we setup the offset in O7 - __ set(offset, O7); - load_offset = load(base, O7, to_reg, type, wide); - } else { - load_offset = code_offset(); - switch(type) { - case T_BOOLEAN: // fall through - case T_BYTE : __ ldsb(base, offset, to_reg->as_register()); break; - case T_CHAR : __ lduh(base, offset, to_reg->as_register()); break; - case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break; - case T_INT : __ ld(base, offset, to_reg->as_register()); break; - case T_LONG : - if (!unaligned && !PatchALot) { - __ ldx(base, offset, to_reg->as_register_lo()); - } else { - assert(base != to_reg->as_register_lo(), "can't handle this"); - assert(O7 != to_reg->as_register_lo(), "can't handle this"); - __ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_lo()); - __ lduw(base, offset + lo_word_offset_in_bytes, O7); // in case O7 is base or offset, use it last - __ sllx(to_reg->as_register_lo(), 32, to_reg->as_register_lo()); - __ or3(to_reg->as_register_lo(), O7, to_reg->as_register_lo()); - } - break; - case T_METADATA: __ ld_ptr(base, offset, to_reg->as_register()); break; - case T_ADDRESS: - if (offset == oopDesc::klass_offset_in_bytes() && UseCompressedClassPointers) { - __ lduw(base, offset, to_reg->as_register()); - __ decode_klass_not_null(to_reg->as_register()); - } else - { - __ ld_ptr(base, offset, to_reg->as_register()); - } - break; - case T_ARRAY : // fall through - case T_OBJECT: - { - if (UseCompressedOops && !wide) { - __ lduw(base, offset, to_reg->as_register()); - __ decode_heap_oop(to_reg->as_register()); - } else { - __ ld_ptr(base, offset, to_reg->as_register()); - } - break; - } - case T_FLOAT: __ ldf(FloatRegisterImpl::S, base, offset, to_reg->as_float_reg()); break; - case T_DOUBLE: - { - FloatRegister reg = to_reg->as_double_reg(); - // split unaligned loads - if (unaligned || PatchALot) { - __ ldf(FloatRegisterImpl::S, base, offset + 4, reg->successor()); - __ ldf(FloatRegisterImpl::S, base, offset, reg); - } else { - __ ldf(FloatRegisterImpl::D, base, offset, to_reg->as_double_reg()); - } - break; - } - default : ShouldNotReachHere(); - } - if (is_reference_type(type)) { - __ verify_oop(to_reg->as_register()); - } - } - return load_offset; -} - - -int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide) { - int load_offset = code_offset(); - switch(type) { - case T_BOOLEAN: // fall through - case T_BYTE : __ ldsb(base, disp, to_reg->as_register()); break; - case T_CHAR : __ lduh(base, disp, to_reg->as_register()); break; - case T_SHORT : __ ldsh(base, disp, to_reg->as_register()); break; - case T_INT : __ ld(base, disp, to_reg->as_register()); break; - case T_ADDRESS: __ ld_ptr(base, disp, to_reg->as_register()); break; - case T_ARRAY : // fall through - case T_OBJECT: - { - if (UseCompressedOops && !wide) { - __ lduw(base, disp, to_reg->as_register()); - __ decode_heap_oop(to_reg->as_register()); - } else { - __ ld_ptr(base, disp, to_reg->as_register()); - } - break; - } - case T_FLOAT: __ ldf(FloatRegisterImpl::S, base, disp, to_reg->as_float_reg()); break; - case T_DOUBLE: __ ldf(FloatRegisterImpl::D, base, disp, to_reg->as_double_reg()); break; - case T_LONG : - __ ldx(base, disp, to_reg->as_register_lo()); - break; - default : ShouldNotReachHere(); - } - if (is_reference_type(type)) { - __ verify_oop(to_reg->as_register()); - } - return load_offset; -} - -void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { - LIR_Const* c = src->as_constant_ptr(); - switch (c->type()) { - case T_INT: - case T_FLOAT: { - Register src_reg = O7; - int value = c->as_jint_bits(); - if (value == 0) { - src_reg = G0; - } else { - __ set(value, O7); - } - Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); - __ stw(src_reg, addr.base(), addr.disp()); - break; - } - case T_ADDRESS: { - Register src_reg = O7; - int value = c->as_jint_bits(); - if (value == 0) { - src_reg = G0; - } else { - __ set(value, O7); - } - Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); - __ st_ptr(src_reg, addr.base(), addr.disp()); - break; - } - case T_OBJECT: { - Register src_reg = O7; - jobject2reg(c->as_jobject(), src_reg); - Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); - __ st_ptr(src_reg, addr.base(), addr.disp()); - break; - } - case T_LONG: - case T_DOUBLE: { - Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix()); - - Register tmp = O7; - int value_lo = c->as_jint_lo_bits(); - if (value_lo == 0) { - tmp = G0; - } else { - __ set(value_lo, O7); - } - __ stw(tmp, addr.base(), addr.disp() + lo_word_offset_in_bytes); - int value_hi = c->as_jint_hi_bits(); - if (value_hi == 0) { - tmp = G0; - } else { - __ set(value_hi, O7); - } - __ stw(tmp, addr.base(), addr.disp() + hi_word_offset_in_bytes); - break; - } - default: - Unimplemented(); - } -} - - -void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { - LIR_Const* c = src->as_constant_ptr(); - LIR_Address* addr = dest->as_address_ptr(); - Register base = addr->base()->as_pointer_register(); - int offset = -1; - - switch (c->type()) { - case T_FLOAT: type = T_INT; // Float constants are stored by int store instructions. - case T_INT: - case T_ADDRESS: { - LIR_Opr tmp = FrameMap::O7_opr; - int value = c->as_jint_bits(); - if (value == 0) { - tmp = FrameMap::G0_opr; - } else if (Assembler::is_simm13(value)) { - __ set(value, O7); - } - if (addr->index()->is_valid()) { - assert(addr->disp() == 0, "must be zero"); - offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide); - } else { - assert(Assembler::is_simm13(addr->disp()), "can't handle larger addresses"); - offset = store(tmp, base, addr->disp(), type, wide, false); - } - break; - } - case T_LONG: - case T_DOUBLE: { - assert(!addr->index()->is_valid(), "can't handle reg reg address here"); - assert(Assembler::is_simm13(addr->disp()) && - Assembler::is_simm13(addr->disp() + 4), "can't handle larger addresses"); - - LIR_Opr tmp = FrameMap::O7_opr; - int value_lo = c->as_jint_lo_bits(); - if (value_lo == 0) { - tmp = FrameMap::G0_opr; - } else { - __ set(value_lo, O7); - } - offset = store(tmp, base, addr->disp() + lo_word_offset_in_bytes, T_INT, wide, false); - int value_hi = c->as_jint_hi_bits(); - if (value_hi == 0) { - tmp = FrameMap::G0_opr; - } else { - __ set(value_hi, O7); - } - store(tmp, base, addr->disp() + hi_word_offset_in_bytes, T_INT, wide, false); - break; - } - case T_OBJECT: { - jobject obj = c->as_jobject(); - LIR_Opr tmp; - if (obj == NULL) { - tmp = FrameMap::G0_opr; - } else { - tmp = FrameMap::O7_opr; - jobject2reg(c->as_jobject(), O7); - } - // handle either reg+reg or reg+disp address - if (addr->index()->is_valid()) { - assert(addr->disp() == 0, "must be zero"); - offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide); - } else { - assert(Assembler::is_simm13(addr->disp()), "can't handle larger addresses"); - offset = store(tmp, base, addr->disp(), type, wide, false); - } - - break; - } - default: - Unimplemented(); - } - if (info != NULL) { - assert(offset != -1, "offset should've been set"); - add_debug_info_for_null_check(offset, info); - } -} - - -void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { - LIR_Const* c = src->as_constant_ptr(); - LIR_Opr to_reg = dest; - - switch (c->type()) { - case T_INT: - case T_ADDRESS: - { - jint con = c->as_jint(); - if (to_reg->is_single_cpu()) { - assert(patch_code == lir_patch_none, "no patching handled here"); - __ set(con, to_reg->as_register()); - } else { - ShouldNotReachHere(); - assert(to_reg->is_single_fpu(), "wrong register kind"); - - __ set(con, O7); - Address temp_slot(SP, (frame::register_save_words * wordSize) + STACK_BIAS); - __ st(O7, temp_slot); - __ ldf(FloatRegisterImpl::S, temp_slot, to_reg->as_float_reg()); - } - } - break; - - case T_LONG: - { - jlong con = c->as_jlong(); - - if (to_reg->is_double_cpu()) { - __ set(con, to_reg->as_register_lo()); - } else if (to_reg->is_single_cpu()) { - __ set(con, to_reg->as_register()); - } else { - ShouldNotReachHere(); - assert(to_reg->is_double_fpu(), "wrong register kind"); - Address temp_slot_lo(SP, ((frame::register_save_words ) * wordSize) + STACK_BIAS); - Address temp_slot_hi(SP, ((frame::register_save_words) * wordSize) + (longSize/2) + STACK_BIAS); - __ set(low(con), O7); - __ st(O7, temp_slot_lo); - __ set(high(con), O7); - __ st(O7, temp_slot_hi); - __ ldf(FloatRegisterImpl::D, temp_slot_lo, to_reg->as_double_reg()); - } - } - break; - - case T_OBJECT: - { - if (patch_code == lir_patch_none) { - jobject2reg(c->as_jobject(), to_reg->as_register()); - } else { - jobject2reg_with_patching(to_reg->as_register(), info); - } - } - break; - - case T_METADATA: - { - if (patch_code == lir_patch_none) { - metadata2reg(c->as_metadata(), to_reg->as_register()); - } else { - klass2reg_with_patching(to_reg->as_register(), info); - } - } - break; - - case T_FLOAT: - { - address const_addr = __ float_constant(c->as_jfloat()); - if (const_addr == NULL) { - bailout("const section overflow"); - break; - } - RelocationHolder rspec = internal_word_Relocation::spec(const_addr); - AddressLiteral const_addrlit(const_addr, rspec); - if (to_reg->is_single_fpu()) { - __ patchable_sethi(const_addrlit, O7); - __ relocate(rspec); - __ ldf(FloatRegisterImpl::S, O7, const_addrlit.low10(), to_reg->as_float_reg()); - - } else { - assert(to_reg->is_single_cpu(), "Must be a cpu register."); - - __ set(const_addrlit, O7); - __ ld(O7, 0, to_reg->as_register()); - } - } - break; - - case T_DOUBLE: - { - address const_addr = __ double_constant(c->as_jdouble()); - if (const_addr == NULL) { - bailout("const section overflow"); - break; - } - RelocationHolder rspec = internal_word_Relocation::spec(const_addr); - - if (to_reg->is_double_fpu()) { - AddressLiteral const_addrlit(const_addr, rspec); - __ patchable_sethi(const_addrlit, O7); - __ relocate(rspec); - __ ldf (FloatRegisterImpl::D, O7, const_addrlit.low10(), to_reg->as_double_reg()); - } else { - assert(to_reg->is_double_cpu(), "Must be a long register."); - __ set(jlong_cast(c->as_jdouble()), to_reg->as_register_lo()); - } - - } - break; - - default: - ShouldNotReachHere(); - } -} - -Address LIR_Assembler::as_Address(LIR_Address* addr) { - Register reg = addr->base()->as_pointer_register(); - LIR_Opr index = addr->index(); - if (index->is_illegal()) { - return Address(reg, addr->disp()); - } else { - assert (addr->disp() == 0, "unsupported address mode"); - return Address(reg, index->as_pointer_register()); - } -} - - -void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { - switch (type) { - case T_INT: - case T_FLOAT: { - Register tmp = O7; - Address from = frame_map()->address_for_slot(src->single_stack_ix()); - Address to = frame_map()->address_for_slot(dest->single_stack_ix()); - __ lduw(from.base(), from.disp(), tmp); - __ stw(tmp, to.base(), to.disp()); - break; - } - case T_ADDRESS: - case T_OBJECT: { - Register tmp = O7; - Address from = frame_map()->address_for_slot(src->single_stack_ix()); - Address to = frame_map()->address_for_slot(dest->single_stack_ix()); - __ ld_ptr(from.base(), from.disp(), tmp); - __ st_ptr(tmp, to.base(), to.disp()); - break; - } - case T_LONG: - case T_DOUBLE: { - Register tmp = O7; - Address from = frame_map()->address_for_double_slot(src->double_stack_ix()); - Address to = frame_map()->address_for_double_slot(dest->double_stack_ix()); - __ lduw(from.base(), from.disp(), tmp); - __ stw(tmp, to.base(), to.disp()); - __ lduw(from.base(), from.disp() + 4, tmp); - __ stw(tmp, to.base(), to.disp() + 4); - break; - } - - default: - ShouldNotReachHere(); - } -} - - -Address LIR_Assembler::as_Address_hi(LIR_Address* addr) { - Address base = as_Address(addr); - return Address(base.base(), base.disp() + hi_word_offset_in_bytes); -} - - -Address LIR_Assembler::as_Address_lo(LIR_Address* addr) { - Address base = as_Address(addr); - return Address(base.base(), base.disp() + lo_word_offset_in_bytes); -} - - -void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, - LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide, bool unaligned) { - - assert(type != T_METADATA, "load of metadata ptr not supported"); - LIR_Address* addr = src_opr->as_address_ptr(); - LIR_Opr to_reg = dest; - - Register src = addr->base()->as_pointer_register(); - Register disp_reg = noreg; - int disp_value = addr->disp(); - bool needs_patching = (patch_code != lir_patch_none); - - if (addr->base()->type() == T_OBJECT) { - __ verify_oop(src); - } - - PatchingStub* patch = NULL; - if (needs_patching) { - patch = new PatchingStub(_masm, PatchingStub::access_field_id); - assert(!to_reg->is_double_cpu() || - patch_code == lir_patch_none || - patch_code == lir_patch_normal, "patching doesn't match register"); - } - - if (addr->index()->is_illegal()) { - if (!Assembler::is_simm13(disp_value) && (!unaligned || Assembler::is_simm13(disp_value + 4))) { - if (needs_patching) { - __ patchable_set(0, O7); - } else { - __ set(disp_value, O7); - } - disp_reg = O7; - } - } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_pointer_register(), O7); - src = O7; - } else { - disp_reg = addr->index()->as_pointer_register(); - assert(disp_value == 0, "can't handle 3 operand addresses"); - } - - // remember the offset of the load. The patching_epilog must be done - // before the call to add_debug_info, otherwise the PcDescs don't get - // entered in increasing order. - int offset = code_offset(); - - assert(disp_reg != noreg || Assembler::is_simm13(disp_value), "should have set this up"); - if (disp_reg == noreg) { - offset = load(src, disp_value, to_reg, type, wide, unaligned); - } else { - assert(!unaligned, "can't handle this"); - offset = load(src, disp_reg, to_reg, type, wide); - } - - if (patch != NULL) { - patching_epilog(patch, patch_code, src, info); - } - if (info != NULL) add_debug_info_for_null_check(offset, info); -} - - -void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { - Address addr; - if (src->is_single_word()) { - addr = frame_map()->address_for_slot(src->single_stack_ix()); - } else if (src->is_double_word()) { - addr = frame_map()->address_for_double_slot(src->double_stack_ix()); - } - - bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0; - load(addr.base(), addr.disp(), dest, dest->type(), true /*wide*/, unaligned); -} - - -void LIR_Assembler::reg2stack(LIR_Opr from_reg, LIR_Opr dest, BasicType type, bool pop_fpu_stack) { - Address addr; - if (dest->is_single_word()) { - addr = frame_map()->address_for_slot(dest->single_stack_ix()); - } else if (dest->is_double_word()) { - addr = frame_map()->address_for_slot(dest->double_stack_ix()); - } - bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0; - store(from_reg, addr.base(), addr.disp(), from_reg->type(), true /*wide*/, unaligned); -} - - -void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) { - if (from_reg->is_float_kind() && to_reg->is_float_kind()) { - if (from_reg->is_double_fpu()) { - // double to double moves - assert(to_reg->is_double_fpu(), "should match"); - __ fmov(FloatRegisterImpl::D, from_reg->as_double_reg(), to_reg->as_double_reg()); - } else { - // float to float moves - assert(to_reg->is_single_fpu(), "should match"); - __ fmov(FloatRegisterImpl::S, from_reg->as_float_reg(), to_reg->as_float_reg()); - } - } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) { - if (from_reg->is_double_cpu()) { - __ mov(from_reg->as_pointer_register(), to_reg->as_pointer_register()); - } else if (to_reg->is_double_cpu()) { - // int to int moves - __ mov(from_reg->as_register(), to_reg->as_register_lo()); - } else { - // int to int moves - __ mov(from_reg->as_register(), to_reg->as_register()); - } - } else { - ShouldNotReachHere(); - } - if (is_reference_type(to_reg->type())) { - __ verify_oop(to_reg->as_register()); - } -} - -void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, - LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, - bool wide, bool unaligned) { - assert(type != T_METADATA, "store of metadata ptr not supported"); - LIR_Address* addr = dest->as_address_ptr(); - - Register src = addr->base()->as_pointer_register(); - Register disp_reg = noreg; - int disp_value = addr->disp(); - bool needs_patching = (patch_code != lir_patch_none); - - if (addr->base()->is_oop_register()) { - __ verify_oop(src); - } - - PatchingStub* patch = NULL; - if (needs_patching) { - patch = new PatchingStub(_masm, PatchingStub::access_field_id); - assert(!from_reg->is_double_cpu() || - patch_code == lir_patch_none || - patch_code == lir_patch_normal, "patching doesn't match register"); - } - - if (addr->index()->is_illegal()) { - if (!Assembler::is_simm13(disp_value) && (!unaligned || Assembler::is_simm13(disp_value + 4))) { - if (needs_patching) { - __ patchable_set(0, O7); - } else { - __ set(disp_value, O7); - } - disp_reg = O7; - } - } else if (unaligned || PatchALot) { - __ add(src, addr->index()->as_pointer_register(), O7); - src = O7; - } else { - disp_reg = addr->index()->as_pointer_register(); - assert(disp_value == 0, "can't handle 3 operand addresses"); - } - - // remember the offset of the store. The patching_epilog must be done - // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get - // entered in increasing order. - int offset; - - assert(disp_reg != noreg || Assembler::is_simm13(disp_value), "should have set this up"); - if (disp_reg == noreg) { - offset = store(from_reg, src, disp_value, type, wide, unaligned); - } else { - assert(!unaligned, "can't handle this"); - offset = store(from_reg, src, disp_reg, type, wide); - } - - if (patch != NULL) { - patching_epilog(patch, patch_code, src, info); - } - - if (info != NULL) add_debug_info_for_null_check(offset, info); -} - - -void LIR_Assembler::return_op(LIR_Opr result) { - if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { - __ reserved_stack_check(); - } - __ ld_ptr(Address(G2_thread, Thread::polling_page_offset()), L0); - __ relocate(relocInfo::poll_return_type); - __ ld_ptr(L0, 0, G0); - __ ret(); - __ delayed()->restore(); -} - - -int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { - __ ld_ptr(Address(G2_thread, Thread::polling_page_offset()), tmp->as_register()); - if (info != NULL) { - add_debug_info_for_branch(info); - } - int offset = __ offset(); - - __ relocate(relocInfo::poll_type); - __ ld_ptr(tmp->as_register(), 0, G0); - return offset; -} - - -void LIR_Assembler::emit_static_call_stub() { - address call_pc = __ pc(); - address stub = __ start_a_stub(call_stub_size()); - if (stub == NULL) { - bailout("static call stub overflow"); - return; - } - - int start = __ offset(); - __ relocate(static_stub_Relocation::spec(call_pc)); - - __ set_metadata(NULL, G5); - // must be set to -1 at code generation time - AddressLiteral addrlit(-1); - __ jump_to(addrlit, G3); - __ delayed()->nop(); - - assert(__ offset() - start <= call_stub_size(), "stub too big"); - __ end_a_stub(); -} - - -void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) { - if (opr1->is_single_fpu()) { - __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, opr1->as_float_reg(), opr2->as_float_reg()); - } else if (opr1->is_double_fpu()) { - __ fcmp(FloatRegisterImpl::D, Assembler::fcc0, opr1->as_double_reg(), opr2->as_double_reg()); - } else if (opr1->is_single_cpu()) { - if (opr2->is_constant()) { - switch (opr2->as_constant_ptr()->type()) { - case T_INT: - { jint con = opr2->as_constant_ptr()->as_jint(); - if (Assembler::is_simm13(con)) { - __ cmp(opr1->as_register(), con); - } else { - __ set(con, O7); - __ cmp(opr1->as_register(), O7); - } - } - break; - - case T_OBJECT: - // there are only equal/notequal comparisions on objects - { jobject con = opr2->as_constant_ptr()->as_jobject(); - if (con == NULL) { - __ cmp(opr1->as_register(), 0); - } else { - jobject2reg(con, O7); - __ cmp(opr1->as_register(), O7); - } - } - break; - - case T_METADATA: - // We only need, for now, comparison with NULL for metadata. - { assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops"); - Metadata* m = opr2->as_constant_ptr()->as_metadata(); - if (m == NULL) { - __ cmp(opr1->as_register(), 0); - } else { - ShouldNotReachHere(); - } - } - break; - - default: - ShouldNotReachHere(); - break; - } - } else { - if (opr2->is_address()) { - LIR_Address * addr = opr2->as_address_ptr(); - BasicType type = addr->type(); - if ( type == T_OBJECT ) __ ld_ptr(as_Address(addr), O7); - else __ ld(as_Address(addr), O7); - __ cmp(opr1->as_register(), O7); - } else { - __ cmp(opr1->as_register(), opr2->as_register()); - } - } - } else if (opr1->is_double_cpu()) { - Register xlo = opr1->as_register_lo(); - Register xhi = opr1->as_register_hi(); - if (opr2->is_constant() && opr2->as_jlong() == 0) { - assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "only handles these cases"); - __ orcc(xhi, G0, G0); - } else if (opr2->is_register()) { - Register ylo = opr2->as_register_lo(); - Register yhi = opr2->as_register_hi(); - __ cmp(xlo, ylo); - } else { - ShouldNotReachHere(); - } - } else if (opr1->is_address()) { - LIR_Address * addr = opr1->as_address_ptr(); - BasicType type = addr->type(); - assert (opr2->is_constant(), "Checking"); - if ( type == T_OBJECT ) __ ld_ptr(as_Address(addr), O7); - else __ ld(as_Address(addr), O7); - __ cmp(O7, opr2->as_constant_ptr()->as_jint()); - } else { - ShouldNotReachHere(); - } -} - - -void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op){ - if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) { - bool is_unordered_less = (code == lir_ucmp_fd2i); - if (left->is_single_fpu()) { - __ float_cmp(true, is_unordered_less ? -1 : 1, left->as_float_reg(), right->as_float_reg(), dst->as_register()); - } else if (left->is_double_fpu()) { - __ float_cmp(false, is_unordered_less ? -1 : 1, left->as_double_reg(), right->as_double_reg(), dst->as_register()); - } else { - ShouldNotReachHere(); - } - } else if (code == lir_cmp_l2i) { - __ lcmp(left->as_register_lo(), right->as_register_lo(), dst->as_register()); - } else { - ShouldNotReachHere(); - } -} - - -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { - Assembler::Condition acond; - switch (condition) { - case lir_cond_equal: acond = Assembler::equal; break; - case lir_cond_notEqual: acond = Assembler::notEqual; break; - case lir_cond_less: acond = Assembler::less; break; - case lir_cond_lessEqual: acond = Assembler::lessEqual; break; - case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break; - case lir_cond_greater: acond = Assembler::greater; break; - case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break; - case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break; - default: ShouldNotReachHere(); - }; - - if (opr1->is_constant() && opr1->type() == T_INT) { - Register dest = result->as_register(); - // load up first part of constant before branch - // and do the rest in the delay slot. - if (!Assembler::is_simm13(opr1->as_jint())) { - __ sethi(opr1->as_jint(), dest); - } - } else if (opr1->is_constant()) { - const2reg(opr1, result, lir_patch_none, NULL); - } else if (opr1->is_register()) { - reg2reg(opr1, result); - } else if (opr1->is_stack()) { - stack2reg(opr1, result, result->type()); - } else { - ShouldNotReachHere(); - } - Label skip; - if (type == T_INT) { - __ br(acond, false, Assembler::pt, skip); - } else { - __ brx(acond, false, Assembler::pt, skip); // checks icc on 32bit and xcc on 64bit - } - if (opr1->is_constant() && opr1->type() == T_INT) { - Register dest = result->as_register(); - if (Assembler::is_simm13(opr1->as_jint())) { - __ delayed()->or3(G0, opr1->as_jint(), dest); - } else { - // the sethi has been done above, so just put in the low 10 bits - __ delayed()->or3(dest, opr1->as_jint() & 0x3ff, dest); - } - } else { - // can't do anything useful in the delay slot - __ delayed()->nop(); - } - if (opr2->is_constant()) { - const2reg(opr2, result, lir_patch_none, NULL); - } else if (opr2->is_register()) { - reg2reg(opr2, result); - } else if (opr2->is_stack()) { - stack2reg(opr2, result, result->type()); - } else { - ShouldNotReachHere(); - } - __ bind(skip); -} - - -void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack) { - assert(info == NULL, "unused on this code path"); - assert(left->is_register(), "wrong items state"); - assert(dest->is_register(), "wrong items state"); - - if (right->is_register()) { - if (dest->is_float_kind()) { - - FloatRegister lreg, rreg, res; - FloatRegisterImpl::Width w; - if (right->is_single_fpu()) { - w = FloatRegisterImpl::S; - lreg = left->as_float_reg(); - rreg = right->as_float_reg(); - res = dest->as_float_reg(); - } else { - w = FloatRegisterImpl::D; - lreg = left->as_double_reg(); - rreg = right->as_double_reg(); - res = dest->as_double_reg(); - } - - switch (code) { - case lir_add: __ fadd(w, lreg, rreg, res); break; - case lir_sub: __ fsub(w, lreg, rreg, res); break; - case lir_mul: // fall through - case lir_mul_strictfp: __ fmul(w, lreg, rreg, res); break; - case lir_div: // fall through - case lir_div_strictfp: __ fdiv(w, lreg, rreg, res); break; - default: ShouldNotReachHere(); - } - - } else if (dest->is_double_cpu()) { - Register dst_lo = dest->as_register_lo(); - Register op1_lo = left->as_pointer_register(); - Register op2_lo = right->as_pointer_register(); - - switch (code) { - case lir_add: - __ add(op1_lo, op2_lo, dst_lo); - break; - - case lir_sub: - __ sub(op1_lo, op2_lo, dst_lo); - break; - - default: ShouldNotReachHere(); - } - } else { - assert (right->is_single_cpu(), "Just Checking"); - - Register lreg = left->as_register(); - Register res = dest->as_register(); - Register rreg = right->as_register(); - switch (code) { - case lir_add: __ add (lreg, rreg, res); break; - case lir_sub: __ sub (lreg, rreg, res); break; - case lir_mul: __ mulx (lreg, rreg, res); break; - default: ShouldNotReachHere(); - } - } - } else { - assert (right->is_constant(), "must be constant"); - - if (dest->is_single_cpu()) { - Register lreg = left->as_register(); - Register res = dest->as_register(); - int simm13 = right->as_constant_ptr()->as_jint(); - - switch (code) { - case lir_add: __ add (lreg, simm13, res); break; - case lir_sub: __ sub (lreg, simm13, res); break; - case lir_mul: __ mulx (lreg, simm13, res); break; - default: ShouldNotReachHere(); - } - } else { - Register lreg = left->as_pointer_register(); - Register res = dest->as_register_lo(); - long con = right->as_constant_ptr()->as_jlong(); - assert(Assembler::is_simm13(con), "must be simm13"); - - switch (code) { - case lir_add: __ add (lreg, (int)con, res); break; - case lir_sub: __ sub (lreg, (int)con, res); break; - case lir_mul: __ mulx (lreg, (int)con, res); break; - default: ShouldNotReachHere(); - } - } - } -} - -void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) { - switch (code) { - case lir_tan: { - assert(thread->is_valid(), "preserve the thread object for performance reasons"); - assert(dest->as_double_reg() == F0, "the result will be in f0/f1"); - break; - } - case lir_sqrt: { - assert(!thread->is_valid(), "there is no need for a thread_reg for dsqrt"); - FloatRegister src_reg = value->as_double_reg(); - FloatRegister dst_reg = dest->as_double_reg(); - __ fsqrt(FloatRegisterImpl::D, src_reg, dst_reg); - break; - } - case lir_abs: { - assert(!thread->is_valid(), "there is no need for a thread_reg for fabs"); - FloatRegister src_reg = value->as_double_reg(); - FloatRegister dst_reg = dest->as_double_reg(); - __ fabs(FloatRegisterImpl::D, src_reg, dst_reg); - break; - } - default: { - ShouldNotReachHere(); - break; - } - } -} - - -void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { - if (right->is_constant()) { - if (dest->is_single_cpu()) { - int simm13 = right->as_constant_ptr()->as_jint(); - switch (code) { - case lir_logic_and: __ and3 (left->as_register(), simm13, dest->as_register()); break; - case lir_logic_or: __ or3 (left->as_register(), simm13, dest->as_register()); break; - case lir_logic_xor: __ xor3 (left->as_register(), simm13, dest->as_register()); break; - default: ShouldNotReachHere(); - } - } else { - long c = right->as_constant_ptr()->as_jlong(); - assert(c == (int)c && Assembler::is_simm13(c), "out of range"); - int simm13 = (int)c; - switch (code) { - case lir_logic_and: - __ and3 (left->as_register_lo(), simm13, dest->as_register_lo()); - break; - - case lir_logic_or: - __ or3 (left->as_register_lo(), simm13, dest->as_register_lo()); - break; - - case lir_logic_xor: - __ xor3 (left->as_register_lo(), simm13, dest->as_register_lo()); - break; - - default: ShouldNotReachHere(); - } - } - } else { - assert(right->is_register(), "right should be in register"); - - if (dest->is_single_cpu()) { - switch (code) { - case lir_logic_and: __ and3 (left->as_register(), right->as_register(), dest->as_register()); break; - case lir_logic_or: __ or3 (left->as_register(), right->as_register(), dest->as_register()); break; - case lir_logic_xor: __ xor3 (left->as_register(), right->as_register(), dest->as_register()); break; - default: ShouldNotReachHere(); - } - } else { - Register l = (left->is_single_cpu() && left->is_oop_register()) ? left->as_register() : - left->as_register_lo(); - Register r = (right->is_single_cpu() && right->is_oop_register()) ? right->as_register() : - right->as_register_lo(); - - switch (code) { - case lir_logic_and: __ and3 (l, r, dest->as_register_lo()); break; - case lir_logic_or: __ or3 (l, r, dest->as_register_lo()); break; - case lir_logic_xor: __ xor3 (l, r, dest->as_register_lo()); break; - default: ShouldNotReachHere(); - } - } - } -} - - -int LIR_Assembler::shift_amount(BasicType t) { - int elem_size = type2aelembytes(t); - switch (elem_size) { - case 1 : return 0; - case 2 : return 1; - case 4 : return 2; - case 8 : return 3; - } - ShouldNotReachHere(); - return -1; -} - - -void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { - assert(exceptionOop->as_register() == Oexception, "should match"); - assert(exceptionPC->as_register() == Oissuing_pc, "should match"); - - info->add_register_oop(exceptionOop); - - // reuse the debug info from the safepoint poll for the throw op itself - address pc_for_athrow = __ pc(); - int pc_for_athrow_offset = __ offset(); - RelocationHolder rspec = internal_word_Relocation::spec(pc_for_athrow); - __ set(pc_for_athrow, Oissuing_pc, rspec); - add_call_info(pc_for_athrow_offset, info); // for exception handler - - __ call(Runtime1::entry_for(Runtime1::handle_exception_id), relocInfo::runtime_call_type); - __ delayed()->nop(); -} - - -void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { - assert(exceptionOop->as_register() == Oexception, "should match"); - - __ br(Assembler::always, false, Assembler::pt, _unwind_handler_entry); - __ delayed()->nop(); -} - -void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { - Register src = op->src()->as_register(); - Register dst = op->dst()->as_register(); - Register src_pos = op->src_pos()->as_register(); - Register dst_pos = op->dst_pos()->as_register(); - Register length = op->length()->as_register(); - Register tmp = op->tmp()->as_register(); - Register tmp2 = O7; - - int flags = op->flags(); - ciArrayKlass* default_type = op->expected_type(); - BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; - if (basic_type == T_ARRAY) basic_type = T_OBJECT; - - // higher 32bits must be null - __ sra(dst_pos, 0, dst_pos); - __ sra(src_pos, 0, src_pos); - __ sra(length, 0, length); - - // set up the arraycopy stub information - ArrayCopyStub* stub = op->stub(); - - // always do stub if no type information is available. it's ok if - // the known type isn't loaded since the code sanity checks - // in debug mode and the type isn't required when we know the exact type - // also check that the type is an array type. - if (op->expected_type() == NULL) { - __ mov(src, O0); - __ mov(src_pos, O1); - __ mov(dst, O2); - __ mov(dst_pos, O3); - __ mov(length, O4); - address copyfunc_addr = StubRoutines::generic_arraycopy(); - assert(copyfunc_addr != NULL, "generic arraycopy stub required"); - -#ifndef PRODUCT - if (PrintC1Statistics) { - address counter = (address)&Runtime1::_generic_arraycopystub_cnt; - __ inc_counter(counter, G1, G3); - } -#endif - __ call_VM_leaf(tmp, copyfunc_addr); - - __ xor3(O0, -1, tmp); - __ sub(length, tmp, length); - __ add(src_pos, tmp, src_pos); - __ cmp_zero_and_br(Assembler::less, O0, *stub->entry()); - __ delayed()->add(dst_pos, tmp, dst_pos); - __ bind(*stub->continuation()); - return; - } - - assert(default_type != NULL && default_type->is_array_klass(), "must be true at this point"); - - // make sure src and dst are non-null and load array length - if (flags & LIR_OpArrayCopy::src_null_check) { - __ tst(src); - __ brx(Assembler::equal, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - - if (flags & LIR_OpArrayCopy::dst_null_check) { - __ tst(dst); - __ brx(Assembler::equal, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - - // If the compiler was not able to prove that exact type of the source or the destination - // of the arraycopy is an array type, check at runtime if the source or the destination is - // an instance type. - if (flags & LIR_OpArrayCopy::type_check) { - if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) { - __ load_klass(dst, tmp); - __ lduw(tmp, in_bytes(Klass::layout_helper_offset()), tmp2); - __ cmp(tmp2, Klass::_lh_neutral_value); - __ br(Assembler::greaterEqual, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - - if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) { - __ load_klass(src, tmp); - __ lduw(tmp, in_bytes(Klass::layout_helper_offset()), tmp2); - __ cmp(tmp2, Klass::_lh_neutral_value); - __ br(Assembler::greaterEqual, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - } - - if (flags & LIR_OpArrayCopy::src_pos_positive_check) { - // test src_pos register - __ cmp_zero_and_br(Assembler::less, src_pos, *stub->entry()); - __ delayed()->nop(); - } - - if (flags & LIR_OpArrayCopy::dst_pos_positive_check) { - // test dst_pos register - __ cmp_zero_and_br(Assembler::less, dst_pos, *stub->entry()); - __ delayed()->nop(); - } - - if (flags & LIR_OpArrayCopy::length_positive_check) { - // make sure length isn't negative - __ cmp_zero_and_br(Assembler::less, length, *stub->entry()); - __ delayed()->nop(); - } - - if (flags & LIR_OpArrayCopy::src_range_check) { - __ ld(src, arrayOopDesc::length_offset_in_bytes(), tmp2); - __ add(length, src_pos, tmp); - __ cmp(tmp2, tmp); - __ br(Assembler::carrySet, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - - if (flags & LIR_OpArrayCopy::dst_range_check) { - __ ld(dst, arrayOopDesc::length_offset_in_bytes(), tmp2); - __ add(length, dst_pos, tmp); - __ cmp(tmp2, tmp); - __ br(Assembler::carrySet, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - } - - int shift = shift_amount(basic_type); - - if (flags & LIR_OpArrayCopy::type_check) { - // We don't know the array types are compatible - if (basic_type != T_OBJECT) { - // Simple test for basic type arrays - if (UseCompressedClassPointers) { - // We don't need decode because we just need to compare - __ lduw(src, oopDesc::klass_offset_in_bytes(), tmp); - __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2); - __ cmp(tmp, tmp2); - __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry()); - } else { - __ ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp); - __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2); - __ cmp(tmp, tmp2); - __ brx(Assembler::notEqual, false, Assembler::pt, *stub->entry()); - } - __ delayed()->nop(); - } else { - // For object arrays, if src is a sub class of dst then we can - // safely do the copy. - address copyfunc_addr = StubRoutines::checkcast_arraycopy(); - - Label cont, slow; - assert_different_registers(tmp, tmp2, G3, G1); - - __ load_klass(src, G3); - __ load_klass(dst, G1); - - __ check_klass_subtype_fast_path(G3, G1, tmp, tmp2, &cont, copyfunc_addr == NULL ? stub->entry() : &slow, NULL); - - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - - __ cmp(G3, 0); - if (copyfunc_addr != NULL) { // use stub if available - // src is not a sub class of dst so we have to do a - // per-element check. - __ br(Assembler::notEqual, false, Assembler::pt, cont); - __ delayed()->nop(); - - __ bind(slow); - - int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray; - if ((flags & mask) != mask) { - // Check that at least both of them object arrays. - assert(flags & mask, "one of the two should be known to be an object array"); - - if (!(flags & LIR_OpArrayCopy::src_objarray)) { - __ load_klass(src, tmp); - } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { - __ load_klass(dst, tmp); - } - int lh_offset = in_bytes(Klass::layout_helper_offset()); - - __ lduw(tmp, lh_offset, tmp2); - - jint objArray_lh = Klass::array_layout_helper(T_OBJECT); - __ set(objArray_lh, tmp); - __ cmp(tmp, tmp2); - __ br(Assembler::notEqual, false, Assembler::pt, *stub->entry()); - __ delayed()->nop(); - } - - Register src_ptr = O0; - Register dst_ptr = O1; - Register len = O2; - Register chk_off = O3; - Register super_k = O4; - - __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr); - if (shift == 0) { - __ add(src_ptr, src_pos, src_ptr); - } else { - __ sll(src_pos, shift, tmp); - __ add(src_ptr, tmp, src_ptr); - } - - __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr); - if (shift == 0) { - __ add(dst_ptr, dst_pos, dst_ptr); - } else { - __ sll(dst_pos, shift, tmp); - __ add(dst_ptr, tmp, dst_ptr); - } - __ mov(length, len); - __ load_klass(dst, tmp); - - int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); - __ ld_ptr(tmp, ek_offset, super_k); - - int sco_offset = in_bytes(Klass::super_check_offset_offset()); - __ lduw(super_k, sco_offset, chk_off); - - __ call_VM_leaf(tmp, copyfunc_addr); - -#ifndef PRODUCT - if (PrintC1Statistics) { - Label failed; - __ br_notnull_short(O0, Assembler::pn, failed); - __ inc_counter((address)&Runtime1::_arraycopy_checkcast_cnt, G1, G3); - __ bind(failed); - } -#endif - - __ br_null(O0, false, Assembler::pt, *stub->continuation()); - __ delayed()->xor3(O0, -1, tmp); - -#ifndef PRODUCT - if (PrintC1Statistics) { - __ inc_counter((address)&Runtime1::_arraycopy_checkcast_attempt_cnt, G1, G3); - } -#endif - - __ sub(length, tmp, length); - __ add(src_pos, tmp, src_pos); - __ br(Assembler::always, false, Assembler::pt, *stub->entry()); - __ delayed()->add(dst_pos, tmp, dst_pos); - - __ bind(cont); - } else { - __ br(Assembler::equal, false, Assembler::pn, *stub->entry()); - __ delayed()->nop(); - __ bind(cont); - } - } - } - -#ifdef ASSERT - if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) { - // Sanity check the known type with the incoming class. For the - // primitive case the types must match exactly with src.klass and - // dst.klass each exactly matching the default type. For the - // object array case, if no type check is needed then either the - // dst type is exactly the expected type and the src type is a - // subtype which we can't check or src is the same array as dst - // but not necessarily exactly of type default_type. - Label known_ok, halt; - metadata2reg(op->expected_type()->constant_encoding(), tmp); - if (UseCompressedClassPointers) { - // tmp holds the default type. It currently comes uncompressed after the - // load of a constant, so encode it. - __ encode_klass_not_null(tmp); - // load the raw value of the dst klass, since we will be comparing - // uncompressed values directly. - __ lduw(dst, oopDesc::klass_offset_in_bytes(), tmp2); - if (basic_type != T_OBJECT) { - __ cmp(tmp, tmp2); - __ br(Assembler::notEqual, false, Assembler::pn, halt); - // load the raw value of the src klass. - __ delayed()->lduw(src, oopDesc::klass_offset_in_bytes(), tmp2); - __ cmp_and_br_short(tmp, tmp2, Assembler::equal, Assembler::pn, known_ok); - } else { - __ cmp(tmp, tmp2); - __ br(Assembler::equal, false, Assembler::pn, known_ok); - __ delayed()->cmp(src, dst); - __ brx(Assembler::equal, false, Assembler::pn, known_ok); - __ delayed()->nop(); - } - } else { - __ ld_ptr(dst, oopDesc::klass_offset_in_bytes(), tmp2); - if (basic_type != T_OBJECT) { - __ cmp(tmp, tmp2); - __ brx(Assembler::notEqual, false, Assembler::pn, halt); - __ delayed()->ld_ptr(src, oopDesc::klass_offset_in_bytes(), tmp2); - __ cmp_and_brx_short(tmp, tmp2, Assembler::equal, Assembler::pn, known_ok); - } else { - __ cmp(tmp, tmp2); - __ brx(Assembler::equal, false, Assembler::pn, known_ok); - __ delayed()->cmp(src, dst); - __ brx(Assembler::equal, false, Assembler::pn, known_ok); - __ delayed()->nop(); - } - } - __ bind(halt); - __ stop("incorrect type information in arraycopy"); - __ bind(known_ok); - } -#endif - -#ifndef PRODUCT - if (PrintC1Statistics) { - address counter = Runtime1::arraycopy_count_address(basic_type); - __ inc_counter(counter, G1, G3); - } -#endif - - Register src_ptr = O0; - Register dst_ptr = O1; - Register len = O2; - - __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr); - if (shift == 0) { - __ add(src_ptr, src_pos, src_ptr); - } else { - __ sll(src_pos, shift, tmp); - __ add(src_ptr, tmp, src_ptr); - } - - __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr); - if (shift == 0) { - __ add(dst_ptr, dst_pos, dst_ptr); - } else { - __ sll(dst_pos, shift, tmp); - __ add(dst_ptr, tmp, dst_ptr); - } - - bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; - bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; - const char *name; - address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); - - // arraycopy stubs takes a length in number of elements, so don't scale it. - __ mov(length, len); - __ call_VM_leaf(tmp, entry); - - __ bind(*stub->continuation()); -} - - -void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) { - if (dest->is_single_cpu()) { - if (left->type() == T_OBJECT) { - switch (code) { - case lir_shl: __ sllx (left->as_register(), count->as_register(), dest->as_register()); break; - case lir_shr: __ srax (left->as_register(), count->as_register(), dest->as_register()); break; - case lir_ushr: __ srl (left->as_register(), count->as_register(), dest->as_register()); break; - default: ShouldNotReachHere(); - } - } else - switch (code) { - case lir_shl: __ sll (left->as_register(), count->as_register(), dest->as_register()); break; - case lir_shr: __ sra (left->as_register(), count->as_register(), dest->as_register()); break; - case lir_ushr: __ srl (left->as_register(), count->as_register(), dest->as_register()); break; - default: ShouldNotReachHere(); - } - } else { - switch (code) { - case lir_shl: __ sllx (left->as_register_lo(), count->as_register(), dest->as_register_lo()); break; - case lir_shr: __ srax (left->as_register_lo(), count->as_register(), dest->as_register_lo()); break; - case lir_ushr: __ srlx (left->as_register_lo(), count->as_register(), dest->as_register_lo()); break; - default: ShouldNotReachHere(); - } - } -} - - -void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) { - if (left->type() == T_OBJECT) { - count = count & 63; // shouldn't shift by more than sizeof(intptr_t) - Register l = left->as_register(); - Register d = dest->as_register_lo(); - switch (code) { - case lir_shl: __ sllx (l, count, d); break; - case lir_shr: __ srax (l, count, d); break; - case lir_ushr: __ srlx (l, count, d); break; - default: ShouldNotReachHere(); - } - return; - } - - if (dest->is_single_cpu()) { - count = count & 0x1F; // Java spec - switch (code) { - case lir_shl: __ sll (left->as_register(), count, dest->as_register()); break; - case lir_shr: __ sra (left->as_register(), count, dest->as_register()); break; - case lir_ushr: __ srl (left->as_register(), count, dest->as_register()); break; - default: ShouldNotReachHere(); - } - } else if (dest->is_double_cpu()) { - count = count & 63; // Java spec - switch (code) { - case lir_shl: __ sllx (left->as_pointer_register(), count, dest->as_pointer_register()); break; - case lir_shr: __ srax (left->as_pointer_register(), count, dest->as_pointer_register()); break; - case lir_ushr: __ srlx (left->as_pointer_register(), count, dest->as_pointer_register()); break; - default: ShouldNotReachHere(); - } - } else { - ShouldNotReachHere(); - } -} - - -void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { - assert(op->tmp1()->as_register() == G1 && - op->tmp2()->as_register() == G3 && - op->tmp3()->as_register() == G4 && - op->obj()->as_register() == O0 && - op->klass()->as_register() == G5, "must be"); - if (op->init_check()) { - add_debug_info_for_null_check_here(op->stub()->info()); - __ ldub(op->klass()->as_register(), - in_bytes(InstanceKlass::init_state_offset()), - op->tmp1()->as_register()); - __ cmp(op->tmp1()->as_register(), InstanceKlass::fully_initialized); - __ br(Assembler::notEqual, false, Assembler::pn, *op->stub()->entry()); - __ delayed()->nop(); - } - __ allocate_object(op->obj()->as_register(), - op->tmp1()->as_register(), - op->tmp2()->as_register(), - op->tmp3()->as_register(), - op->header_size(), - op->object_size(), - op->klass()->as_register(), - *op->stub()->entry()); - __ bind(*op->stub()->continuation()); - __ verify_oop(op->obj()->as_register()); -} - - -void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { - assert(op->tmp1()->as_register() == G1 && - op->tmp2()->as_register() == G3 && - op->tmp3()->as_register() == G4 && - op->tmp4()->as_register() == O1 && - op->klass()->as_register() == G5, "must be"); - - __ signx(op->len()->as_register()); - if (UseSlowPath || - (!UseFastNewObjectArray && is_reference_type(op->type())) || - (!UseFastNewTypeArray && !is_reference_type(op->type()))) { - __ br(Assembler::always, false, Assembler::pt, *op->stub()->entry()); - __ delayed()->nop(); - } else { - __ allocate_array(op->obj()->as_register(), - op->len()->as_register(), - op->tmp1()->as_register(), - op->tmp2()->as_register(), - op->tmp3()->as_register(), - arrayOopDesc::header_size(op->type()), - type2aelembytes(op->type()), - op->klass()->as_register(), - *op->stub()->entry()); - } - __ bind(*op->stub()->continuation()); -} - - -void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias, - ciMethodData *md, ciProfileData *data, - Register recv, Register tmp1, Label* update_done) { - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - // See if the receiver is receiver[n]. - Address receiver_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - - mdo_offset_bias); - __ ld_ptr(receiver_addr, tmp1); - __ verify_klass_ptr(tmp1); - __ cmp_and_brx_short(recv, tmp1, Assembler::notEqual, Assembler::pt, next_test); - Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - - mdo_offset_bias); - __ ld_ptr(data_addr, tmp1); - __ add(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, data_addr); - __ ba(*update_done); - __ delayed()->nop(); - __ bind(next_test); - } - - // Didn't find receiver; find next empty slot and fill it in - for (i = 0; i < VirtualCallData::row_limit(); i++) { - Label next_test; - Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - - mdo_offset_bias); - __ ld_ptr(recv_addr, tmp1); - __ br_notnull_short(tmp1, Assembler::pt, next_test); - __ st_ptr(recv, recv_addr); - __ set(DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - - mdo_offset_bias); - __ ba(*update_done); - __ delayed()->nop(); - __ bind(next_test); - } -} - - -void LIR_Assembler::setup_md_access(ciMethod* method, int bci, - ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) { - md = method->method_data_or_null(); - assert(md != NULL, "Sanity"); - data = md->bci_to_data(bci); - assert(data != NULL, "need data for checkcast"); - assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); - if (!Assembler::is_simm13(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { - // The offset is large so bias the mdo by the base of the slot so - // that the ld can use simm13s to reference the slots of the data - mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); - } -} - -void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { - // we always need a stub for the failure case. - CodeStub* stub = op->stub(); - Register obj = op->object()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); - Register dst = op->result_opr()->as_register(); - Register Rtmp1 = op->tmp3()->as_register(); - ciKlass* k = op->klass(); - - - if (obj == k_RInfo) { - k_RInfo = klass_RInfo; - klass_RInfo = obj; - } - - ciMethodData* md; - ciProfileData* data; - int mdo_offset_bias = 0; - if (op->should_profile()) { - ciMethod* method = op->profiled_method(); - assert(method != NULL, "Should have method"); - setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); - - Label not_null; - __ br_notnull_short(obj, Assembler::pn, not_null); - Register mdo = k_RInfo; - Register data_val = Rtmp1; - metadata2reg(md->constant_encoding(), mdo); - if (mdo_offset_bias > 0) { - __ set(mdo_offset_bias, data_val); - __ add(mdo, data_val, mdo); - } - Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias); - __ ldub(flags_addr, data_val); - __ or3(data_val, BitData::null_seen_byte_constant(), data_val); - __ stb(data_val, flags_addr); - __ ba(*obj_is_null); - __ delayed()->nop(); - __ bind(not_null); - } else { - __ br_null(obj, false, Assembler::pn, *obj_is_null); - __ delayed()->nop(); - } - - Label profile_cast_failure, profile_cast_success; - Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; - Label *success_target = op->should_profile() ? &profile_cast_success : success; - - // patching may screw with our temporaries on sparc, - // so let's do it before loading the class - if (k->is_loaded()) { - metadata2reg(k->constant_encoding(), k_RInfo); - } else { - klass2reg_with_patching(k_RInfo, op->info_for_patch()); - } - assert(obj != k_RInfo, "must be different"); - - // get object class - // not a safepoint as obj null check happens earlier - __ load_klass(obj, klass_RInfo); - if (op->fast_check()) { - assert_different_registers(klass_RInfo, k_RInfo); - __ cmp(k_RInfo, klass_RInfo); - __ brx(Assembler::notEqual, false, Assembler::pt, *failure_target); - __ delayed()->nop(); - } else { - bool need_slow_path = true; - if (k->is_loaded()) { - if ((int) k->super_check_offset() != in_bytes(Klass::secondary_super_cache_offset())) - need_slow_path = false; - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, noreg, - (need_slow_path ? success_target : NULL), - failure_target, NULL, - RegisterOrConstant(k->super_check_offset())); - } else { - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, - failure_target, NULL); - } - if (need_slow_path) { - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *failure_target); - __ delayed()->nop(); - // Fall through to success case - } - } - - if (op->should_profile()) { - Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; - assert_different_registers(obj, mdo, recv, tmp1); - __ bind(profile_cast_success); - metadata2reg(md->constant_encoding(), mdo); - if (mdo_offset_bias > 0) { - __ set(mdo_offset_bias, tmp1); - __ add(mdo, tmp1, mdo); - } - __ load_klass(obj, recv); - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, success); - // Jump over the failure case - __ ba(*success); - __ delayed()->nop(); - // Cast failure case - __ bind(profile_cast_failure); - metadata2reg(md->constant_encoding(), mdo); - if (mdo_offset_bias > 0) { - __ set(mdo_offset_bias, tmp1); - __ add(mdo, tmp1, mdo); - } - Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); - __ ld_ptr(data_addr, tmp1); - __ sub(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, data_addr); - __ ba(*failure); - __ delayed()->nop(); - } - __ ba(*success); - __ delayed()->nop(); -} - -void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { - LIR_Code code = op->code(); - if (code == lir_store_check) { - Register value = op->object()->as_register(); - Register array = op->array()->as_register(); - Register k_RInfo = op->tmp1()->as_register(); - Register klass_RInfo = op->tmp2()->as_register(); - Register Rtmp1 = op->tmp3()->as_register(); - - __ verify_oop(value); - CodeStub* stub = op->stub(); - // check if it needs to be profiled - ciMethodData* md; - ciProfileData* data; - int mdo_offset_bias = 0; - if (op->should_profile()) { - ciMethod* method = op->profiled_method(); - assert(method != NULL, "Should have method"); - setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); - } - Label profile_cast_success, profile_cast_failure, done; - Label *success_target = op->should_profile() ? &profile_cast_success : &done; - Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); - - if (op->should_profile()) { - Label not_null; - __ br_notnull_short(value, Assembler::pn, not_null); - Register mdo = k_RInfo; - Register data_val = Rtmp1; - metadata2reg(md->constant_encoding(), mdo); - if (mdo_offset_bias > 0) { - __ set(mdo_offset_bias, data_val); - __ add(mdo, data_val, mdo); - } - Address flags_addr(mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias); - __ ldub(flags_addr, data_val); - __ or3(data_val, BitData::null_seen_byte_constant(), data_val); - __ stb(data_val, flags_addr); - __ ba_short(done); - __ bind(not_null); - } else { - __ br_null_short(value, Assembler::pn, done); - } - add_debug_info_for_null_check_here(op->info_for_exception()); - __ load_klass(array, k_RInfo); - __ load_klass(value, klass_RInfo); - - // get instance klass - __ ld_ptr(Address(k_RInfo, ObjArrayKlass::element_klass_offset()), k_RInfo); - // perform the fast part of the checking logic - __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, O7, success_target, failure_target, NULL); - - // call out-of-line instance of __ check_klass_subtype_slow_path(...): - assert(klass_RInfo == G3 && k_RInfo == G1, "incorrect call setup"); - __ call(Runtime1::entry_for(Runtime1::slow_subtype_check_id), relocInfo::runtime_call_type); - __ delayed()->nop(); - __ cmp(G3, 0); - __ br(Assembler::equal, false, Assembler::pn, *failure_target); - __ delayed()->nop(); - // fall through to the success case - - if (op->should_profile()) { - Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; - assert_different_registers(value, mdo, recv, tmp1); - __ bind(profile_cast_success); - metadata2reg(md->constant_encoding(), mdo); - if (mdo_offset_bias > 0) { - __ set(mdo_offset_bias, tmp1); - __ add(mdo, tmp1, mdo); - } - __ load_klass(value, recv); - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done); - __ ba_short(done); - // Cast failure case - __ bind(profile_cast_failure); - metadata2reg(md->constant_encoding(), mdo); - if (mdo_offset_bias > 0) { - __ set(mdo_offset_bias, tmp1); - __ add(mdo, tmp1, mdo); - } - Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); - __ ld_ptr(data_addr, tmp1); - __ sub(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, data_addr); - __ ba(*stub->entry()); - __ delayed()->nop(); - } - __ bind(done); - } else if (code == lir_checkcast) { - Register obj = op->object()->as_register(); - Register dst = op->result_opr()->as_register(); - Label success; - emit_typecheck_helper(op, &success, op->stub()->entry(), &success); - __ bind(success); - __ mov(obj, dst); - } else if (code == lir_instanceof) { - Register obj = op->object()->as_register(); - Register dst = op->result_opr()->as_register(); - Label success, failure, done; - emit_typecheck_helper(op, &success, &failure, &failure); - __ bind(failure); - __ set(0, dst); - __ ba_short(done); - __ bind(success); - __ set(1, dst); - __ bind(done); - } else { - ShouldNotReachHere(); - } - -} - - -void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { - if (op->code() == lir_cas_long) { - assert(VM_Version::supports_cx8(), "wrong machine"); - Register addr = op->addr()->as_pointer_register(); - Register cmp_value_lo = op->cmp_value()->as_register_lo(); - Register cmp_value_hi = op->cmp_value()->as_register_hi(); - Register new_value_lo = op->new_value()->as_register_lo(); - Register new_value_hi = op->new_value()->as_register_hi(); - Register t1 = op->tmp1()->as_register(); - Register t2 = op->tmp2()->as_register(); - __ mov(cmp_value_lo, t1); - __ mov(new_value_lo, t2); - // perform the compare and swap operation - __ casx(addr, t1, t2); - // generate condition code - if the swap succeeded, t2 ("new value" reg) was - // overwritten with the original value in "addr" and will be equal to t1. - __ cmp(t1, t2); - } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { - Register addr = op->addr()->as_pointer_register(); - Register cmp_value = op->cmp_value()->as_register(); - Register new_value = op->new_value()->as_register(); - Register t1 = op->tmp1()->as_register(); - Register t2 = op->tmp2()->as_register(); - __ mov(cmp_value, t1); - __ mov(new_value, t2); - if (op->code() == lir_cas_obj) { - if (UseCompressedOops) { - __ encode_heap_oop(t1); - __ encode_heap_oop(t2); - __ cas(addr, t1, t2); - } else { - __ cas_ptr(addr, t1, t2); - } - } else { - __ cas(addr, t1, t2); - } - __ cmp(t1, t2); - } else { - Unimplemented(); - } -} - -void LIR_Assembler::breakpoint() { - __ breakpoint_trap(); -} - - -void LIR_Assembler::push(LIR_Opr opr) { - Unimplemented(); -} - - -void LIR_Assembler::pop(LIR_Opr opr) { - Unimplemented(); -} - - -void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst_opr) { - Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no); - Register dst = dst_opr->as_register(); - Register reg = mon_addr.base(); - int offset = mon_addr.disp(); - // compute pointer to BasicLock - if (mon_addr.is_simm13()) { - __ add(reg, offset, dst); - } else { - __ set(offset, dst); - __ add(dst, reg, dst); - } -} - -void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { - assert(op->crc()->is_single_cpu(), "crc must be register"); - assert(op->val()->is_single_cpu(), "byte value must be register"); - assert(op->result_opr()->is_single_cpu(), "result must be register"); - Register crc = op->crc()->as_register(); - Register val = op->val()->as_register(); - Register table = op->result_opr()->as_register(); - Register res = op->result_opr()->as_register(); - - assert_different_registers(val, crc, table); - - __ set(ExternalAddress(StubRoutines::crc_table_addr()), table); - __ not1(crc); - __ clruwu(crc); - __ update_byte_crc32(crc, val, table); - __ not1(crc); - - __ mov(crc, res); -} - -void LIR_Assembler::emit_lock(LIR_OpLock* op) { - Register obj = op->obj_opr()->as_register(); - Register hdr = op->hdr_opr()->as_register(); - Register lock = op->lock_opr()->as_register(); - - // obj may not be an oop - if (op->code() == lir_lock) { - MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); - if (UseFastLocking) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - // add debug info for NullPointerException only if one is possible - if (op->info() != NULL) { - add_debug_info_for_null_check_here(op->info()); - } - __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); - } else { - // always do slow locking - // note: the slow locking code could be inlined here, however if we use - // slow locking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow locking code is the same in either case which simplifies - // debugging - __ br(Assembler::always, false, Assembler::pt, *op->stub()->entry()); - __ delayed()->nop(); - } - } else { - assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); - if (UseFastLocking) { - assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); - __ unlock_object(hdr, obj, lock, *op->stub()->entry()); - } else { - // always do slow unlocking - // note: the slow unlocking code could be inlined here, however if we use - // slow unlocking, speed doesn't matter anyway and this solution is - // simpler and requires less duplicated code - additionally, the - // slow unlocking code is the same in either case which simplifies - // debugging - __ br(Assembler::always, false, Assembler::pt, *op->stub()->entry()); - __ delayed()->nop(); - } - } - __ bind(*op->stub()->continuation()); -} - - -void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { - ciMethod* method = op->profiled_method(); - int bci = op->profiled_bci(); - ciMethod* callee = op->profiled_callee(); - - // Update counter for all call types - ciMethodData* md = method->method_data_or_null(); - assert(md != NULL, "Sanity"); - ciProfileData* data = md->bci_to_data(bci); - assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); - assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); - Register mdo = op->mdo()->as_register(); - assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated"); - Register tmp1 = op->tmp1()->as_register_lo(); - metadata2reg(md->constant_encoding(), mdo); - int mdo_offset_bias = 0; - if (!Assembler::is_simm13(md->byte_offset_of_slot(data, CounterData::count_offset()) + - data->size_in_bytes())) { - // The offset is large so bias the mdo by the base of the slot so - // that the ld can use simm13s to reference the slots of the data - mdo_offset_bias = md->byte_offset_of_slot(data, CounterData::count_offset()); - __ set(mdo_offset_bias, O7); - __ add(mdo, O7, mdo); - } - - Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); - // Perform additional virtual call profiling for invokevirtual and - // invokeinterface bytecodes - if (op->should_profile_receiver_type()) { - assert(op->recv()->is_single_cpu(), "recv must be allocated"); - Register recv = op->recv()->as_register(); - assert_different_registers(mdo, tmp1, recv); - assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls"); - ciKlass* known_klass = op->known_holder(); - if (C1OptimizeVirtualCallProfiling && known_klass != NULL) { - // We know the type that will be seen at this call site; we can - // statically update the MethodData* rather than needing to do - // dynamic tests on the receiver type - - // NOTE: we should probably put a lock around this search to - // avoid collisions by concurrent compilations - ciVirtualCallData* vc_data = (ciVirtualCallData*) data; - uint i; - for (i = 0; i < VirtualCallData::row_limit(); i++) { - ciKlass* receiver = vc_data->receiver(i); - if (known_klass->equals(receiver)) { - Address data_addr(mdo, md->byte_offset_of_slot(data, - VirtualCallData::receiver_count_offset(i)) - - mdo_offset_bias); - __ ld_ptr(data_addr, tmp1); - __ add(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, data_addr); - return; - } - } - - // Receiver type not found in profile data; select an empty slot - - // Note that this is less efficient than it should be because it - // always does a write to the receiver part of the - // VirtualCallData rather than just the first time - for (i = 0; i < VirtualCallData::row_limit(); i++) { - ciKlass* receiver = vc_data->receiver(i); - if (receiver == NULL) { - Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - - mdo_offset_bias); - metadata2reg(known_klass->constant_encoding(), tmp1); - __ st_ptr(tmp1, recv_addr); - Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - - mdo_offset_bias); - __ ld_ptr(data_addr, tmp1); - __ add(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, data_addr); - return; - } - } - } else { - __ load_klass(recv, recv); - Label update_done; - type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done); - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - __ ld_ptr(counter_addr, tmp1); - __ add(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, counter_addr); - - __ bind(update_done); - } - } else { - // Static call - __ ld_ptr(counter_addr, tmp1); - __ add(tmp1, DataLayout::counter_increment, tmp1); - __ st_ptr(tmp1, counter_addr); - } -} - -void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { - Register obj = op->obj()->as_register(); - Register tmp1 = op->tmp()->as_pointer_register(); - Register tmp2 = G1; - Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); - ciKlass* exact_klass = op->exact_klass(); - intptr_t current_klass = op->current_klass(); - bool not_null = op->not_null(); - bool no_conflict = op->no_conflict(); - - Label update, next, none; - - bool do_null = !not_null; - bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; - bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; - - assert(do_null || do_update, "why are we here?"); - assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); - - __ verify_oop(obj); - - if (tmp1 != obj) { - __ mov(obj, tmp1); - } - if (do_null) { - __ br_notnull_short(tmp1, Assembler::pt, update); - if (!TypeEntries::was_null_seen(current_klass)) { - __ ld_ptr(mdo_addr, tmp1); - __ or3(tmp1, TypeEntries::null_seen, tmp1); - __ st_ptr(tmp1, mdo_addr); - } - if (do_update) { - __ ba(next); - __ delayed()->nop(); - } -#ifdef ASSERT - } else { - __ br_notnull_short(tmp1, Assembler::pt, update); - __ stop("unexpect null obj"); -#endif - } - - __ bind(update); - - if (do_update) { -#ifdef ASSERT - if (exact_klass != NULL) { - Label ok; - __ load_klass(tmp1, tmp1); - metadata2reg(exact_klass->constant_encoding(), tmp2); - __ cmp_and_br_short(tmp1, tmp2, Assembler::equal, Assembler::pt, ok); - __ stop("exact klass and actual klass differ"); - __ bind(ok); - } -#endif - - Label do_update; - __ ld_ptr(mdo_addr, tmp2); - - if (!no_conflict) { - if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { - if (exact_klass != NULL) { - metadata2reg(exact_klass->constant_encoding(), tmp1); - } else { - __ load_klass(tmp1, tmp1); - } - - __ xor3(tmp1, tmp2, tmp1); - __ btst(TypeEntries::type_klass_mask, tmp1); - // klass seen before, nothing to do. The unknown bit may have been - // set already but no need to check. - __ brx(Assembler::zero, false, Assembler::pt, next); - __ delayed()-> - - btst(TypeEntries::type_unknown, tmp1); - // already unknown. Nothing to do anymore. - __ brx(Assembler::notZero, false, Assembler::pt, next); - - if (TypeEntries::is_type_none(current_klass)) { - __ delayed()->btst(TypeEntries::type_mask, tmp2); - __ brx(Assembler::zero, true, Assembler::pt, do_update); - // first time here. Set profile type. - __ delayed()->or3(tmp2, tmp1, tmp2); - } else { - __ delayed()->nop(); - } - } else { - assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && - ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); - - __ btst(TypeEntries::type_unknown, tmp2); - // already unknown. Nothing to do anymore. - __ brx(Assembler::notZero, false, Assembler::pt, next); - __ delayed()->nop(); - } - - // different than before. Cannot keep accurate profile. - __ or3(tmp2, TypeEntries::type_unknown, tmp2); - } else { - // There's a single possible klass at this profile point - assert(exact_klass != NULL, "should be"); - if (TypeEntries::is_type_none(current_klass)) { - metadata2reg(exact_klass->constant_encoding(), tmp1); - __ xor3(tmp1, tmp2, tmp1); - __ btst(TypeEntries::type_klass_mask, tmp1); - __ brx(Assembler::zero, false, Assembler::pt, next); -#ifdef ASSERT - - { - Label ok; - __ delayed()->btst(TypeEntries::type_mask, tmp2); - __ brx(Assembler::zero, true, Assembler::pt, ok); - __ delayed()->nop(); - - __ stop("unexpected profiling mismatch"); - __ bind(ok); - } - // first time here. Set profile type. - __ or3(tmp2, tmp1, tmp2); -#else - // first time here. Set profile type. - __ delayed()->or3(tmp2, tmp1, tmp2); -#endif - - } else { - assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && - ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); - - // already unknown. Nothing to do anymore. - __ btst(TypeEntries::type_unknown, tmp2); - __ brx(Assembler::notZero, false, Assembler::pt, next); - __ delayed()->or3(tmp2, TypeEntries::type_unknown, tmp2); - } - } - - __ bind(do_update); - __ st_ptr(tmp2, mdo_addr); - - __ bind(next); - } -} - -void LIR_Assembler::align_backward_branch_target() { - __ align(OptoLoopAlignment); -} - - -void LIR_Assembler::emit_delay(LIR_OpDelay* op) { - // make sure we are expecting a delay - // this has the side effect of clearing the delay state - // so we can use _masm instead of _masm->delayed() to do the - // code generation. - __ delayed(); - - // make sure we only emit one instruction - int offset = code_offset(); - op->delay_op()->emit_code(this); -#ifdef ASSERT - if (code_offset() - offset != NativeInstruction::nop_instruction_size) { - op->delay_op()->print(); - } - assert(code_offset() - offset == NativeInstruction::nop_instruction_size, - "only one instruction can go in a delay slot"); -#endif - - // we may also be emitting the call info for the instruction - // which we are the delay slot of. - CodeEmitInfo* call_info = op->call_info(); - if (call_info) { - add_call_info(code_offset(), call_info); - } - - if (VerifyStackAtCalls) { - _masm->sub(FP, SP, O7); - _masm->cmp(O7, initial_frame_size_in_bytes()); - _masm->trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0+2 ); - } -} - - -void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { - // tmp must be unused - assert(tmp->is_illegal(), "wasting a register if tmp is allocated"); - assert(left->is_register(), "can only handle registers"); - - if (left->is_single_cpu()) { - __ neg(left->as_register(), dest->as_register()); - } else if (left->is_single_fpu()) { - __ fneg(FloatRegisterImpl::S, left->as_float_reg(), dest->as_float_reg()); - } else if (left->is_double_fpu()) { - __ fneg(FloatRegisterImpl::D, left->as_double_reg(), dest->as_double_reg()); - } else { - assert (left->is_double_cpu(), "Must be a long"); - Register Rlow = left->as_register_lo(); - Register Rhi = left->as_register_hi(); - __ sub(G0, Rlow, dest->as_register_lo()); - } -} - -void LIR_Assembler::rt_call(LIR_Opr result, address dest, - const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { - - // if tmp is invalid, then the function being called doesn't destroy the thread - if (tmp->is_valid()) { - __ save_thread(tmp->as_pointer_register()); - } - __ call(dest, relocInfo::runtime_call_type); - __ delayed()->nop(); - if (info != NULL) { - add_call_info_here(info); - } - if (tmp->is_valid()) { - __ restore_thread(tmp->as_pointer_register()); - } - -#ifdef ASSERT - __ verify_thread(); -#endif // ASSERT -} - - -void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { - ShouldNotReachHere(); - - NEEDS_CLEANUP; - if (type == T_LONG) { - LIR_Address* mem_addr = dest->is_address() ? dest->as_address_ptr() : src->as_address_ptr(); - - // (extended to allow indexed as well as constant displaced for JSR-166) - Register idx = noreg; // contains either constant offset or index - - int disp = mem_addr->disp(); - if (mem_addr->index() == LIR_OprFact::illegalOpr) { - if (!Assembler::is_simm13(disp)) { - idx = O7; - __ set(disp, idx); - } - } else { - assert(disp == 0, "not both indexed and disp"); - idx = mem_addr->index()->as_register(); - } - - int null_check_offset = -1; - - Register base = mem_addr->base()->as_register(); - if (src->is_register() && dest->is_address()) { - // G4 is high half, G5 is low half - // clear the top bits of G5, and scale up G4 - __ srl (src->as_register_lo(), 0, G5); - __ sllx(src->as_register_hi(), 32, G4); - // combine the two halves into the 64 bits of G4 - __ or3(G4, G5, G4); - null_check_offset = __ offset(); - if (idx == noreg) { - __ stx(G4, base, disp); - } else { - __ stx(G4, base, idx); - } - } else if (src->is_address() && dest->is_register()) { - null_check_offset = __ offset(); - if (idx == noreg) { - __ ldx(base, disp, G5); - } else { - __ ldx(base, idx, G5); - } - __ srax(G5, 32, dest->as_register_hi()); // fetch the high half into hi - __ mov (G5, dest->as_register_lo()); // copy low half into lo - } else { - Unimplemented(); - } - if (info != NULL) { - add_debug_info_for_null_check(null_check_offset, info); - } - - } else { - // use normal move for all other volatiles since they don't need - // special handling to remain atomic. - move_op(src, dest, type, lir_patch_none, info, false, false, false); - } -} - -void LIR_Assembler::membar() { - // only StoreLoad membars are ever explicitly needed on sparcs in TSO mode - __ membar( Assembler::Membar_mask_bits(Assembler::StoreLoad) ); -} - -void LIR_Assembler::membar_acquire() { - // no-op on TSO -} - -void LIR_Assembler::membar_release() { - // no-op on TSO -} - -void LIR_Assembler::membar_loadload() { - // no-op - //__ membar(Assembler::Membar_mask_bits(Assembler::loadload)); -} - -void LIR_Assembler::membar_storestore() { - // no-op - //__ membar(Assembler::Membar_mask_bits(Assembler::storestore)); -} - -void LIR_Assembler::membar_loadstore() { - // no-op - //__ membar(Assembler::Membar_mask_bits(Assembler::loadstore)); -} - -void LIR_Assembler::membar_storeload() { - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); -} - -void LIR_Assembler::on_spin_wait() { - Unimplemented(); -} - -// Pack two sequential registers containing 32 bit values -// into a single 64 bit register. -// src and src->successor() are packed into dst -// src and dst may be the same register. -// Note: src is destroyed -void LIR_Assembler::pack64(LIR_Opr src, LIR_Opr dst) { - Register rs = src->as_register(); - Register rd = dst->as_register_lo(); - __ sllx(rs, 32, rs); - __ srl(rs->successor(), 0, rs->successor()); - __ or3(rs, rs->successor(), rd); -} - -// Unpack a 64 bit value in a register into -// two sequential registers. -// src is unpacked into dst and dst->successor() -void LIR_Assembler::unpack64(LIR_Opr src, LIR_Opr dst) { - Register rs = src->as_register_lo(); - Register rd = dst->as_register_hi(); - assert_different_registers(rs, rd, rd->successor()); - __ srlx(rs, 32, rd); - __ srl (rs, 0, rd->successor()); -} - -void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { - const LIR_Address* addr = addr_opr->as_address_ptr(); - assert(addr->scale() == LIR_Address::times_1, "can't handle complex addresses yet"); - const Register dest_reg = dest->as_pointer_register(); - const Register base_reg = addr->base()->as_pointer_register(); - - if (patch_code != lir_patch_none) { - PatchingStub* patch = new PatchingStub(_masm, PatchingStub::access_field_id); - assert(addr->disp() != 0, "must have"); - assert(base_reg != G3_scratch, "invariant"); - __ patchable_set(0, G3_scratch); - patching_epilog(patch, patch_code, base_reg, info); - assert(dest_reg != G3_scratch, "invariant"); - if (addr->index()->is_valid()) { - const Register index_reg = addr->index()->as_pointer_register(); - assert(index_reg != G3_scratch, "invariant"); - __ add(index_reg, G3_scratch, G3_scratch); - } - __ add(base_reg, G3_scratch, dest_reg); - } else { - if (Assembler::is_simm13(addr->disp())) { - if (addr->index()->is_valid()) { - const Register index_reg = addr->index()->as_pointer_register(); - assert(index_reg != G3_scratch, "invariant"); - __ add(base_reg, addr->disp(), G3_scratch); - __ add(index_reg, G3_scratch, dest_reg); - } else { - __ add(base_reg, addr->disp(), dest_reg); - } - } else { - __ set(addr->disp(), G3_scratch); - if (addr->index()->is_valid()) { - const Register index_reg = addr->index()->as_pointer_register(); - assert(index_reg != G3_scratch, "invariant"); - __ add(index_reg, G3_scratch, G3_scratch); - } - __ add(base_reg, G3_scratch, dest_reg); - } - } -} - - -void LIR_Assembler::get_thread(LIR_Opr result_reg) { - assert(result_reg->is_register(), "check"); - __ mov(G2_thread, result_reg->as_register()); -} - -#ifdef ASSERT -// emit run-time assertion -void LIR_Assembler::emit_assert(LIR_OpAssert* op) { - assert(op->code() == lir_assert, "must be"); - - if (op->in_opr1()->is_valid()) { - assert(op->in_opr2()->is_valid(), "both operands must be valid"); - comp_op(op->condition(), op->in_opr1(), op->in_opr2(), op); - } else { - assert(op->in_opr2()->is_illegal(), "both operands must be illegal"); - assert(op->condition() == lir_cond_always, "no other conditions allowed"); - } - - Label ok; - if (op->condition() != lir_cond_always) { - Assembler::Condition acond; - switch (op->condition()) { - case lir_cond_equal: acond = Assembler::equal; break; - case lir_cond_notEqual: acond = Assembler::notEqual; break; - case lir_cond_less: acond = Assembler::less; break; - case lir_cond_lessEqual: acond = Assembler::lessEqual; break; - case lir_cond_greaterEqual: acond = Assembler::greaterEqual; break; - case lir_cond_greater: acond = Assembler::greater; break; - case lir_cond_aboveEqual: acond = Assembler::greaterEqualUnsigned; break; - case lir_cond_belowEqual: acond = Assembler::lessEqualUnsigned; break; - default: ShouldNotReachHere(); - }; - __ br(acond, false, Assembler::pt, ok); - __ delayed()->nop(); - } - if (op->halt()) { - const char* str = __ code_string(op->msg()); - __ stop(str); - } else { - breakpoint(); - } - __ bind(ok); -} -#endif - -void LIR_Assembler::peephole(LIR_List* lir) { - LIR_OpList* inst = lir->instructions_list(); - for (int i = 0; i < inst->length(); i++) { - LIR_Op* op = inst->at(i); - switch (op->code()) { - case lir_cond_float_branch: - case lir_branch: { - LIR_OpBranch* branch = op->as_OpBranch(); - assert(branch->info() == NULL, "shouldn't be state on branches anymore"); - LIR_Op* delay_op = NULL; - // we'd like to be able to pull following instructions into - // this slot but we don't know enough to do it safely yet so - // only optimize block to block control flow. - if (LIRFillDelaySlots && branch->block()) { - LIR_Op* prev = inst->at(i - 1); - if (prev && LIR_Assembler::is_single_instruction(prev) && prev->info() == NULL) { - // swap previous instruction into delay slot - inst->at_put(i - 1, op); - inst->at_put(i, new LIR_OpDelay(prev, op->info())); -#ifndef PRODUCT - if (LIRTracePeephole) { - tty->print_cr("delayed"); - inst->at(i - 1)->print(); - inst->at(i)->print(); - tty->cr(); - } -#endif - continue; - } - } - - if (!delay_op) { - delay_op = new LIR_OpDelay(new LIR_Op0(lir_nop), NULL); - } - inst->insert_before(i + 1, delay_op); - break; - } - case lir_static_call: - case lir_virtual_call: - case lir_icvirtual_call: - case lir_optvirtual_call: - case lir_dynamic_call: { - LIR_Op* prev = inst->at(i - 1); - if (LIRFillDelaySlots && prev && prev->code() == lir_move && prev->info() == NULL && - (op->code() != lir_virtual_call || - !prev->result_opr()->is_single_cpu() || - prev->result_opr()->as_register() != O0) && - LIR_Assembler::is_single_instruction(prev)) { - // Only moves without info can be put into the delay slot. - // Also don't allow the setup of the receiver in the delay - // slot for vtable calls. - inst->at_put(i - 1, op); - inst->at_put(i, new LIR_OpDelay(prev, op->info())); -#ifndef PRODUCT - if (LIRTracePeephole) { - tty->print_cr("delayed"); - inst->at(i - 1)->print(); - inst->at(i)->print(); - tty->cr(); - } -#endif - } else { - LIR_Op* delay_op = new LIR_OpDelay(new LIR_Op0(lir_nop), op->as_OpJavaCall()->info()); - inst->insert_before(i + 1, delay_op); - i++; - } - break; - } - } - } -} - -void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) { - LIR_Address* addr = src->as_address_ptr(); - - assert(data == dest, "swap uses only 2 operands"); - assert (code == lir_xchg, "no xadd on sparc"); - - if (data->type() == T_INT) { - __ swap(as_Address(addr), data->as_register()); - } else if (data->is_oop()) { - Register obj = data->as_register(); - Register narrow = tmp->as_register(); - assert(UseCompressedOops, "swap is 32bit only"); - __ encode_heap_oop(obj, narrow); - __ swap(as_Address(addr), narrow); - __ decode_heap_oop(narrow, obj); - } else { - ShouldNotReachHere(); - } -} - -#undef __ diff --git a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_LIRASSEMBLER_SPARC_HPP -#define CPU_SPARC_C1_LIRASSEMBLER_SPARC_HPP - - private: - - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // - // Sparc load/store emission - // - // The sparc ld/st instructions cannot accomodate displacements > 13 bits long. - // The following "pseudo" sparc instructions (load/store) make it easier to use the indexed addressing mode - // by allowing 32 bit displacements: - // - // When disp <= 13 bits long, a single load or store instruction is emitted with (disp + [d]). - // When disp > 13 bits long, code is emitted to set the displacement into the O7 register, - // and then a load or store is emitted with ([O7] + [d]). - // - - int store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned); - int store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide); - - int load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned); - int load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide); - - void monitorexit(LIR_Opr obj_opr, LIR_Opr lock_opr, Register hdr, int monitor_no); - - int shift_amount(BasicType t); - - static bool is_single_instruction(LIR_Op* op); - - // Record the type of the receiver in ReceiverTypeData - void type_profile_helper(Register mdo, int mdo_offset_bias, - ciMethodData *md, ciProfileData *data, - Register recv, Register tmp1, Label* update_done); - // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot. - void setup_md_access(ciMethod* method, int bci, - ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias); - - enum { - _call_stub_size = 68, - _call_aot_stub_size = 0, - _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(128), - _deopt_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(64) - }; - - public: - void pack64(LIR_Opr src, LIR_Opr dst); - void unpack64(LIR_Opr src, LIR_Opr dst); - -#endif // CPU_SPARC_C1_LIRASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_LIRGenerator_sparc.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -/* - * Copyright (c) 2005, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "c1/c1_Compilation.hpp" -#include "c1/c1_FrameMap.hpp" -#include "c1/c1_Instruction.hpp" -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_LIRGenerator.hpp" -#include "c1/c1_Runtime1.hpp" -#include "c1/c1_ValueStack.hpp" -#include "ci/ciArray.hpp" -#include "ci/ciObjArrayKlass.hpp" -#include "ci/ciTypeArrayKlass.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "utilities/powerOfTwo.hpp" -#include "vmreg_sparc.inline.hpp" - -#ifdef ASSERT -#define __ gen()->lir(__FILE__, __LINE__)-> -#else -#define __ gen()->lir()-> -#endif - -void LIRItem::load_byte_item() { - // byte loads use same registers as other loads - load_item(); -} - - -void LIRItem::load_nonconstant() { - LIR_Opr r = value()->operand(); - if (_gen->can_inline_as_constant(value())) { - if (!r->is_constant()) { - r = LIR_OprFact::value_type(value()->type()); - } - _result = r; - } else { - load_item(); - } -} - - -//-------------------------------------------------------------- -// LIRGenerator -//-------------------------------------------------------------- - -LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::Oexception_opr; } -LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::Oissuing_pc_opr; } -LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); } -LIR_Opr LIRGenerator::syncTempOpr() { return new_register(T_OBJECT); } -LIR_Opr LIRGenerator::getThreadTemp() { return rlock_callee_saved(T_LONG); } - -LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { - LIR_Opr opr; - switch (type->tag()) { - case intTag: opr = callee ? FrameMap::I0_opr : FrameMap::O0_opr; break; - case objectTag: opr = callee ? FrameMap::I0_oop_opr : FrameMap::O0_oop_opr; break; - case longTag: opr = callee ? FrameMap::in_long_opr : FrameMap::out_long_opr; break; - case floatTag: opr = FrameMap::F0_opr; break; - case doubleTag: opr = FrameMap::F0_double_opr; break; - - case addressTag: - default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr; - } - - assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch"); - return opr; -} - -LIR_Opr LIRGenerator::rlock_callee_saved(BasicType type) { - LIR_Opr reg = new_register(type); - set_vreg_flag(reg, callee_saved); - return reg; -} - - -LIR_Opr LIRGenerator::rlock_byte(BasicType type) { - return new_register(T_INT); -} - - - - - -//--------- loading items into registers -------------------------------- - -// SPARC cannot inline all constants -bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const { - if (v->type()->as_IntConstant() != NULL) { - return v->type()->as_IntConstant()->value() == 0; - } else if (v->type()->as_LongConstant() != NULL) { - return v->type()->as_LongConstant()->value() == 0L; - } else if (v->type()->as_ObjectConstant() != NULL) { - return v->type()->as_ObjectConstant()->value()->is_null_object(); - } else { - return false; - } -} - - -// only simm13 constants can be inlined -bool LIRGenerator:: can_inline_as_constant(Value i) const { - if (i->type()->as_IntConstant() != NULL) { - return Assembler::is_simm13(i->type()->as_IntConstant()->value()); - } else { - return can_store_as_constant(i, as_BasicType(i->type())); - } -} - - -bool LIRGenerator:: can_inline_as_constant(LIR_Const* c) const { - if (c->type() == T_INT) { - return Assembler::is_simm13(c->as_jint()); - } - return false; -} - - -LIR_Opr LIRGenerator::safepoint_poll_register() { - return new_register(T_INT); -} - - - -LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, - int shift, int disp, BasicType type) { - assert(base->is_register(), "must be"); - intx large_disp = disp; - - // accumulate fixed displacements - if (index->is_constant()) { - large_disp += (intx)(index->as_constant_ptr()->as_jint()) << shift; - index = LIR_OprFact::illegalOpr; - } - - if (index->is_register()) { - // apply the shift and accumulate the displacement - if (shift > 0) { - LIR_Opr tmp = new_pointer_register(); - __ shift_left(index, shift, tmp); - index = tmp; - } - if (large_disp != 0) { - LIR_Opr tmp = new_pointer_register(); - if (Assembler::is_simm13(large_disp)) { - __ add(tmp, LIR_OprFact::intptrConst(large_disp), tmp); - index = tmp; - } else { - __ move(LIR_OprFact::intptrConst(large_disp), tmp); - __ add(tmp, index, tmp); - index = tmp; - } - large_disp = 0; - } - } else if (large_disp != 0 && !Assembler::is_simm13(large_disp)) { - // index is illegal so replace it with the displacement loaded into a register - index = new_pointer_register(); - __ move(LIR_OprFact::intptrConst(large_disp), index); - large_disp = 0; - } - - // at this point we either have base + index or base + displacement - if (large_disp == 0) { - return new LIR_Address(base, index, type); - } else { - assert(Assembler::is_simm13(large_disp), "must be"); - return new LIR_Address(base, large_disp, type); - } -} - - -LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, - BasicType type) { - int elem_size = type2aelembytes(type); - int shift = exact_log2(elem_size); - - LIR_Opr base_opr; - intx offset = arrayOopDesc::base_offset_in_bytes(type); - - if (index_opr->is_constant()) { - intx i = index_opr->as_constant_ptr()->as_jint(); - intx array_offset = i * elem_size; - if (Assembler::is_simm13(array_offset + offset)) { - base_opr = array_opr; - offset = array_offset + offset; - } else { - base_opr = new_pointer_register(); - if (Assembler::is_simm13(array_offset)) { - __ add(array_opr, LIR_OprFact::intptrConst(array_offset), base_opr); - } else { - __ move(LIR_OprFact::intptrConst(array_offset), base_opr); - __ add(base_opr, array_opr, base_opr); - } - } - } else { - if (index_opr->type() == T_INT) { - LIR_Opr tmp = new_register(T_LONG); - __ convert(Bytecodes::_i2l, index_opr, tmp); - index_opr = tmp; - } - - base_opr = new_pointer_register(); - assert (index_opr->is_register(), "Must be register"); - if (shift > 0) { - __ shift_left(index_opr, shift, base_opr); - __ add(base_opr, array_opr, base_opr); - } else { - __ add(index_opr, array_opr, base_opr); - } - } - - return new LIR_Address(base_opr, offset, type); -} - -LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { - LIR_Opr r; - if (type == T_LONG) { - r = LIR_OprFact::longConst(x); - } else if (type == T_INT) { - r = LIR_OprFact::intConst(x); - } else { - ShouldNotReachHere(); - } - if (!Assembler::is_simm13(x)) { - LIR_Opr tmp = new_register(type); - __ move(r, tmp); - return tmp; - } - return r; -} - -void LIRGenerator::increment_counter(address counter, BasicType type, int step) { - LIR_Opr pointer = new_pointer_register(); - __ move(LIR_OprFact::intptrConst(counter), pointer); - LIR_Address* addr = new LIR_Address(pointer, type); - increment_counter(addr, step); -} - -void LIRGenerator::increment_counter(LIR_Address* addr, int step) { - LIR_Opr temp = new_register(addr->type()); - __ move(addr, temp); - __ add(temp, load_immediate(step, addr->type()), temp); - __ move(temp, addr); -} - -void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { - LIR_Opr o7opr = FrameMap::O7_opr; - __ load(new LIR_Address(base, disp, T_INT), o7opr, info); - __ cmp(condition, o7opr, c); -} - - -void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, int disp, BasicType type, CodeEmitInfo* info) { - LIR_Opr o7opr = FrameMap::O7_opr; - __ load(new LIR_Address(base, disp, type), o7opr, info); - __ cmp(condition, reg, o7opr); -} - - -bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) { - assert(left != result, "should be different registers"); - if (is_power_of_2(c + 1)) { - __ shift_left(left, log2_int(c + 1), result); - __ sub(result, left, result); - return true; - } else if (is_power_of_2(c - 1)) { - __ shift_left(left, log2_int(c - 1), result); - __ add(result, left, result); - return true; - } - return false; -} - - -void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) { - BasicType t = item->type(); - LIR_Opr sp_opr = FrameMap::SP_opr; - if ((t == T_LONG || t == T_DOUBLE) && - ((in_bytes(offset_from_sp) - STACK_BIAS) % 8 != 0)) { - __ unaligned_move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t)); - } else { - __ move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t)); - } -} - -void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, ciMethod* profiled_method, int profiled_bci) { - LIR_Opr tmp1 = FrameMap::G1_opr; - LIR_Opr tmp2 = FrameMap::G3_opr; - LIR_Opr tmp3 = FrameMap::G5_opr; - __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); -} - -//---------------------------------------------------------------------- -// visitor functions -//---------------------------------------------------------------------- - -void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { - assert(x->is_pinned(),""); - LIRItem obj(x->obj(), this); - obj.load_item(); - - set_no_result(x); - - LIR_Opr lock = FrameMap::G1_opr; - LIR_Opr scratch = FrameMap::G3_opr; - LIR_Opr hdr = FrameMap::G4_opr; - - CodeEmitInfo* info_for_exception = NULL; - if (x->needs_null_check()) { - info_for_exception = state_for(x); - } - - // this CodeEmitInfo must not have the xhandlers because here the - // object is already locked (xhandlers expects object to be unlocked) - CodeEmitInfo* info = state_for(x, x->state(), true); - monitor_enter(obj.result(), lock, hdr, scratch, x->monitor_no(), info_for_exception, info); -} - - -void LIRGenerator::do_MonitorExit(MonitorExit* x) { - assert(x->is_pinned(),""); - LIRItem obj(x->obj(), this); - obj.dont_load_item(); - - set_no_result(x); - LIR_Opr lock = FrameMap::G1_opr; - LIR_Opr hdr = FrameMap::G3_opr; - LIR_Opr obj_temp = FrameMap::G4_opr; - monitor_exit(obj_temp, lock, hdr, LIR_OprFact::illegalOpr, x->monitor_no()); -} - - -// _ineg, _lneg, _fneg, _dneg -void LIRGenerator::do_NegateOp(NegateOp* x) { - LIRItem value(x->x(), this); - value.load_item(); - LIR_Opr reg = rlock_result(x); - __ negate(value.result(), reg); -} - - - -// for _fadd, _fmul, _fsub, _fdiv, _frem -// _dadd, _dmul, _dsub, _ddiv, _drem -void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { - switch (x->op()) { - case Bytecodes::_fadd: - case Bytecodes::_fmul: - case Bytecodes::_fsub: - case Bytecodes::_fdiv: - case Bytecodes::_dadd: - case Bytecodes::_dmul: - case Bytecodes::_dsub: - case Bytecodes::_ddiv: { - LIRItem left(x->x(), this); - LIRItem right(x->y(), this); - left.load_item(); - right.load_item(); - rlock_result(x); - arithmetic_op_fpu(x->op(), x->operand(), left.result(), right.result(), x->is_strictfp()); - } - break; - - case Bytecodes::_frem: - case Bytecodes::_drem: { - address entry; - switch (x->op()) { - case Bytecodes::_frem: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem); - break; - case Bytecodes::_drem: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem); - break; - default: - ShouldNotReachHere(); - } - LIR_Opr result = call_runtime(x->x(), x->y(), entry, x->type(), NULL); - set_result(x, result); - } - break; - - default: ShouldNotReachHere(); - } -} - - -// for _ladd, _lmul, _lsub, _ldiv, _lrem -void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) { - switch (x->op()) { - case Bytecodes::_lrem: - case Bytecodes::_lmul: - case Bytecodes::_ldiv: { - - if (x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem) { - LIRItem right(x->y(), this); - right.load_item(); - - CodeEmitInfo* info = state_for(x); - LIR_Opr item = right.result(); - assert(item->is_register(), "must be"); - __ cmp(lir_cond_equal, item, LIR_OprFact::longConst(0)); - __ branch(lir_cond_equal, T_LONG, new DivByZeroStub(info)); - } - - address entry; - switch (x->op()) { - case Bytecodes::_lrem: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::lrem); - break; // check if dividend is 0 is done elsewhere - case Bytecodes::_ldiv: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::ldiv); - break; // check if dividend is 0 is done elsewhere - case Bytecodes::_lmul: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::lmul); - break; - default: - ShouldNotReachHere(); - } - - // order of arguments to runtime call is reversed. - LIR_Opr result = call_runtime(x->y(), x->x(), entry, x->type(), NULL); - set_result(x, result); - break; - } - case Bytecodes::_ladd: - case Bytecodes::_lsub: { - LIRItem left(x->x(), this); - LIRItem right(x->y(), this); - left.load_item(); - right.load_item(); - rlock_result(x); - - arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL); - break; - } - default: ShouldNotReachHere(); - } -} - - -// Returns if item is an int constant that can be represented by a simm13 -static bool is_simm13(LIR_Opr item) { - if (item->is_constant() && item->type() == T_INT) { - return Assembler::is_simm13(item->as_constant_ptr()->as_jint()); - } else { - return false; - } -} - - -// for: _iadd, _imul, _isub, _idiv, _irem -void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) { - bool is_div_rem = x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem; - LIRItem left(x->x(), this); - LIRItem right(x->y(), this); - // missing test if instr is commutative and if we should swap - right.load_nonconstant(); - assert(right.is_constant() || right.is_register(), "wrong state of right"); - left.load_item(); - rlock_result(x); - if (is_div_rem) { - CodeEmitInfo* info = state_for(x); - LIR_Opr tmp = FrameMap::G1_opr; - if (x->op() == Bytecodes::_irem) { - __ irem(left.result(), right.result(), x->operand(), tmp, info); - } else if (x->op() == Bytecodes::_idiv) { - __ idiv(left.result(), right.result(), x->operand(), tmp, info); - } - } else { - arithmetic_op_int(x->op(), x->operand(), left.result(), right.result(), FrameMap::G1_opr); - } -} - - -void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) { - ValueTag tag = x->type()->tag(); - assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters"); - switch (tag) { - case floatTag: - case doubleTag: do_ArithmeticOp_FPU(x); return; - case longTag: do_ArithmeticOp_Long(x); return; - case intTag: do_ArithmeticOp_Int(x); return; - } - ShouldNotReachHere(); -} - - -// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr -void LIRGenerator::do_ShiftOp(ShiftOp* x) { - LIRItem value(x->x(), this); - LIRItem count(x->y(), this); - // Long shift destroys count register - if (value.type()->is_long()) { - count.set_destroys_register(); - } - value.load_item(); - // the old backend doesn't support this - if (count.is_constant() && count.type()->as_IntConstant() != NULL && value.type()->is_int()) { - jint c = count.get_jint_constant() & 0x1f; - assert(c >= 0 && c < 32, "should be small"); - count.dont_load_item(); - } else { - count.load_item(); - } - LIR_Opr reg = rlock_result(x); - shift_op(x->op(), reg, value.result(), count.result(), LIR_OprFact::illegalOpr); -} - - -// _iand, _land, _ior, _lor, _ixor, _lxor -void LIRGenerator::do_LogicOp(LogicOp* x) { - LIRItem left(x->x(), this); - LIRItem right(x->y(), this); - - left.load_item(); - right.load_nonconstant(); - LIR_Opr reg = rlock_result(x); - - logic_op(x->op(), reg, left.result(), right.result()); -} - - - -// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg -void LIRGenerator::do_CompareOp(CompareOp* x) { - LIRItem left(x->x(), this); - LIRItem right(x->y(), this); - left.load_item(); - right.load_item(); - LIR_Opr reg = rlock_result(x); - if (x->x()->type()->is_float_kind()) { - Bytecodes::Code code = x->op(); - __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl)); - } else if (x->x()->type()->tag() == longTag) { - __ lcmp2int(left.result(), right.result(), reg); - } else { - Unimplemented(); - } -} - -LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { - LIR_Opr result = new_register(T_INT); - LIR_Opr t1 = FrameMap::G1_opr; - LIR_Opr t2 = FrameMap::G3_opr; - cmp_value.load_item(); - new_value.load_item(); - if (is_reference_type(type)) { - __ cas_obj(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); - } else if (type == T_INT) { - __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); - } else if (type == T_LONG) { - __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), t1, t2); - } else { - Unimplemented(); - } - __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), - result, type); - return result; -} - -LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { - bool is_obj = is_reference_type(type); - LIR_Opr result = new_register(type); - LIR_Opr tmp = LIR_OprFact::illegalOpr; - - value.load_item(); - - if (is_obj) { - tmp = FrameMap::G3_opr; - } - - // Because we want a 2-arg form of xchg - __ move(value.result(), result); - __ xchg(addr, result, result, tmp); - return result; -} - -LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { - Unimplemented(); - return LIR_OprFact::illegalOpr; -} - -void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { - switch (x->id()) { - case vmIntrinsics::_dabs: - case vmIntrinsics::_dsqrt: { - assert(x->number_of_arguments() == 1, "wrong type"); - LIRItem value(x->argument_at(0), this); - value.load_item(); - LIR_Opr dst = rlock_result(x); - - switch (x->id()) { - case vmIntrinsics::_dsqrt: { - __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr); - break; - } - case vmIntrinsics::_dabs: { - __ abs(value.result(), dst, LIR_OprFact::illegalOpr); - break; - } - } - break; - } - case vmIntrinsics::_dlog10: // fall through - case vmIntrinsics::_dlog: // fall through - case vmIntrinsics::_dsin: // fall through - case vmIntrinsics::_dtan: // fall through - case vmIntrinsics::_dcos: // fall through - case vmIntrinsics::_dexp: { - assert(x->number_of_arguments() == 1, "wrong type"); - - address runtime_entry = NULL; - switch (x->id()) { - case vmIntrinsics::_dsin: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); - break; - case vmIntrinsics::_dcos: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); - break; - case vmIntrinsics::_dtan: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); - break; - case vmIntrinsics::_dlog: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); - break; - case vmIntrinsics::_dlog10: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); - break; - case vmIntrinsics::_dexp: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp); - break; - default: - ShouldNotReachHere(); - } - - LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL); - set_result(x, result); - break; - } - case vmIntrinsics::_dpow: { - assert(x->number_of_arguments() == 2, "wrong type"); - address runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow); - LIR_Opr result = call_runtime(x->argument_at(0), x->argument_at(1), runtime_entry, x->type(), NULL); - set_result(x, result); - break; - } - } -} - - -void LIRGenerator::do_ArrayCopy(Intrinsic* x) { - assert(x->number_of_arguments() == 5, "wrong type"); - - // Make all state_for calls early since they can emit code - CodeEmitInfo* info = state_for(x, x->state()); - - // Note: spill caller save before setting the item - LIRItem src (x->argument_at(0), this); - LIRItem src_pos (x->argument_at(1), this); - LIRItem dst (x->argument_at(2), this); - LIRItem dst_pos (x->argument_at(3), this); - LIRItem length (x->argument_at(4), this); - // load all values in callee_save_registers, as this makes the - // parameter passing to the fast case simpler - src.load_item_force (rlock_callee_saved(T_OBJECT)); - src_pos.load_item_force (rlock_callee_saved(T_INT)); - dst.load_item_force (rlock_callee_saved(T_OBJECT)); - dst_pos.load_item_force (rlock_callee_saved(T_INT)); - length.load_item_force (rlock_callee_saved(T_INT)); - - int flags; - ciArrayKlass* expected_type; - arraycopy_helper(x, &flags, &expected_type); - - __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), - length.result(), rlock_callee_saved(T_INT), - expected_type, flags, info); - set_no_result(x); -} - -void LIRGenerator::do_update_CRC32(Intrinsic* x) { - // Make all state_for calls early since they can emit code - LIR_Opr result = rlock_result(x); - int flags = 0; - switch (x->id()) { - case vmIntrinsics::_updateCRC32: { - LIRItem crc(x->argument_at(0), this); - LIRItem val(x->argument_at(1), this); - // val is destroyed by update_crc32 - val.set_destroys_register(); - crc.load_item(); - val.load_item(); - __ update_crc32(crc.result(), val.result(), result); - break; - } - case vmIntrinsics::_updateBytesCRC32: - case vmIntrinsics::_updateByteBufferCRC32: { - - bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32); - - LIRItem crc(x->argument_at(0), this); - LIRItem buf(x->argument_at(1), this); - LIRItem off(x->argument_at(2), this); - LIRItem len(x->argument_at(3), this); - - buf.load_item(); - off.load_nonconstant(); - - LIR_Opr index = off.result(); - int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; - if(off.result()->is_constant()) { - index = LIR_OprFact::illegalOpr; - offset += off.result()->as_jint(); - } - - LIR_Opr base_op = buf.result(); - - if (index->is_valid()) { - LIR_Opr tmp = new_register(T_LONG); - __ convert(Bytecodes::_i2l, index, tmp); - index = tmp; - if (index->is_constant()) { - offset += index->as_constant_ptr()->as_jint(); - index = LIR_OprFact::illegalOpr; - } else if (index->is_register()) { - LIR_Opr tmp2 = new_register(T_LONG); - LIR_Opr tmp3 = new_register(T_LONG); - __ move(base_op, tmp2); - __ move(index, tmp3); - __ add(tmp2, tmp3, tmp2); - base_op = tmp2; - } else { - ShouldNotReachHere(); - } - } - - LIR_Address* a = new LIR_Address(base_op, offset, T_BYTE); - - BasicTypeList signature(3); - signature.append(T_INT); - signature.append(T_ADDRESS); - signature.append(T_INT); - CallingConvention* cc = frame_map()->c_calling_convention(&signature); - const LIR_Opr result_reg = result_register_for(x->type()); - - LIR_Opr addr = new_pointer_register(); - __ leal(LIR_OprFact::address(a), addr); - - crc.load_item_force(cc->at(0)); - __ move(addr, cc->at(1)); - len.load_item_force(cc->at(2)); - - __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), getThreadTemp(), result_reg, cc->args()); - __ move(result_reg, result); - - break; - } - default: { - ShouldNotReachHere(); - } - } -} - -void LIRGenerator::do_update_CRC32C(Intrinsic* x) { - // Make all state_for calls early since they can emit code - LIR_Opr result = rlock_result(x); - int flags = 0; - switch (x->id()) { - case vmIntrinsics::_updateBytesCRC32C: - case vmIntrinsics::_updateDirectByteBufferCRC32C: { - - bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32C); - int array_offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; - - LIRItem crc(x->argument_at(0), this); - LIRItem buf(x->argument_at(1), this); - LIRItem off(x->argument_at(2), this); - LIRItem end(x->argument_at(3), this); - - buf.load_item(); - off.load_nonconstant(); - end.load_nonconstant(); - - // len = end - off - LIR_Opr len = end.result(); - LIR_Opr tmpA = new_register(T_INT); - LIR_Opr tmpB = new_register(T_INT); - __ move(end.result(), tmpA); - __ move(off.result(), tmpB); - __ sub(tmpA, tmpB, tmpA); - len = tmpA; - - LIR_Opr index = off.result(); - - if(off.result()->is_constant()) { - index = LIR_OprFact::illegalOpr; - array_offset += off.result()->as_jint(); - } - - LIR_Opr base_op = buf.result(); - - if (index->is_valid()) { - LIR_Opr tmp = new_register(T_LONG); - __ convert(Bytecodes::_i2l, index, tmp); - index = tmp; - if (index->is_constant()) { - array_offset += index->as_constant_ptr()->as_jint(); - index = LIR_OprFact::illegalOpr; - } else if (index->is_register()) { - LIR_Opr tmp2 = new_register(T_LONG); - LIR_Opr tmp3 = new_register(T_LONG); - __ move(base_op, tmp2); - __ move(index, tmp3); - __ add(tmp2, tmp3, tmp2); - base_op = tmp2; - } else { - ShouldNotReachHere(); - } - } - - LIR_Address* a = new LIR_Address(base_op, array_offset, T_BYTE); - - BasicTypeList signature(3); - signature.append(T_INT); - signature.append(T_ADDRESS); - signature.append(T_INT); - CallingConvention* cc = frame_map()->c_calling_convention(&signature); - const LIR_Opr result_reg = result_register_for(x->type()); - - LIR_Opr addr = new_pointer_register(); - __ leal(LIR_OprFact::address(a), addr); - - crc.load_item_force(cc->at(0)); - __ move(addr, cc->at(1)); - __ move(len, cc->at(2)); - - __ call_runtime_leaf(StubRoutines::updateBytesCRC32C(), getThreadTemp(), result_reg, cc->args()); - __ move(result_reg, result); - - break; - } - default: { - ShouldNotReachHere(); - } - } -} - -void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) { - assert(x->number_of_arguments() == 3, "wrong type"); - assert(UseFMA, "Needs FMA instructions support."); - - LIRItem a(x->argument_at(0), this); - LIRItem b(x->argument_at(1), this); - LIRItem c(x->argument_at(2), this); - - a.load_item(); - b.load_item(); - c.load_item(); - - LIR_Opr ina = a.result(); - LIR_Opr inb = b.result(); - LIR_Opr inc = c.result(); - LIR_Opr res = rlock_result(x); - - switch (x->id()) { - case vmIntrinsics::_fmaF: __ fmaf(ina, inb, inc, res); break; - case vmIntrinsics::_fmaD: __ fmad(ina, inb, inc, res); break; - default: - ShouldNotReachHere(); - break; - } -} - -void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { - fatal("vectorizedMismatch intrinsic is not implemented on this platform"); -} - -// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f -// _i2b, _i2c, _i2s -void LIRGenerator::do_Convert(Convert* x) { - - switch (x->op()) { - case Bytecodes::_f2l: - case Bytecodes::_d2l: - case Bytecodes::_d2i: - case Bytecodes::_l2f: - case Bytecodes::_l2d: { - - address entry; - switch (x->op()) { - case Bytecodes::_l2f: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f); - break; - case Bytecodes::_l2d: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2d); - break; - case Bytecodes::_f2l: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::f2l); - break; - case Bytecodes::_d2l: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::d2l); - break; - case Bytecodes::_d2i: - entry = CAST_FROM_FN_PTR(address, SharedRuntime::d2i); - break; - default: - ShouldNotReachHere(); - } - LIR_Opr result = call_runtime(x->value(), entry, x->type(), NULL); - set_result(x, result); - break; - } - - case Bytecodes::_i2f: - case Bytecodes::_i2d: { - LIRItem value(x->value(), this); - - LIR_Opr reg = rlock_result(x); - // To convert an int to double, we need to load the 32-bit int - // from memory into a single precision floating point register - // (even numbered). Then the sparc fitod instruction takes care - // of the conversion. This is a bit ugly, but is the best way to - // get the int value in a single precision floating point register - value.load_item(); - LIR_Opr tmp = force_to_spill(value.result(), T_FLOAT); - __ convert(x->op(), tmp, reg); - break; - } - break; - - case Bytecodes::_i2l: - case Bytecodes::_i2b: - case Bytecodes::_i2c: - case Bytecodes::_i2s: - case Bytecodes::_l2i: - case Bytecodes::_f2d: - case Bytecodes::_d2f: { // inline code - LIRItem value(x->value(), this); - - value.load_item(); - LIR_Opr reg = rlock_result(x); - __ convert(x->op(), value.result(), reg, false); - } - break; - - case Bytecodes::_f2i: { - LIRItem value (x->value(), this); - value.set_destroys_register(); - value.load_item(); - LIR_Opr reg = rlock_result(x); - set_vreg_flag(reg, must_start_in_memory); - __ convert(x->op(), value.result(), reg, false); - } - break; - - default: ShouldNotReachHere(); - } -} - - -void LIRGenerator::do_NewInstance(NewInstance* x) { - print_if_not_loaded(x); - - // This instruction can be deoptimized in the slow path : use - // O0 as result register. - const LIR_Opr reg = result_register_for(x->type()); - - CodeEmitInfo* info = state_for(x, x->state()); - LIR_Opr tmp1 = FrameMap::G1_oop_opr; - LIR_Opr tmp2 = FrameMap::G3_oop_opr; - LIR_Opr tmp3 = FrameMap::G4_oop_opr; - LIR_Opr tmp4 = FrameMap::O1_oop_opr; - LIR_Opr klass_reg = FrameMap::G5_metadata_opr; - new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3, tmp4, klass_reg, info); - LIR_Opr result = rlock_result(x); - __ move(reg, result); -} - - -void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { - // Evaluate state_for early since it may emit code - CodeEmitInfo* info = state_for(x, x->state()); - - LIRItem length(x->length(), this); - length.load_item(); - - LIR_Opr reg = result_register_for(x->type()); - LIR_Opr tmp1 = FrameMap::G1_oop_opr; - LIR_Opr tmp2 = FrameMap::G3_oop_opr; - LIR_Opr tmp3 = FrameMap::G4_oop_opr; - LIR_Opr tmp4 = FrameMap::O1_oop_opr; - LIR_Opr klass_reg = FrameMap::G5_metadata_opr; - LIR_Opr len = length.result(); - BasicType elem_type = x->elt_type(); - - __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); - - CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); - __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); - - LIR_Opr result = rlock_result(x); - __ move(reg, result); -} - - -void LIRGenerator::do_NewObjectArray(NewObjectArray* x) { - // Evaluate state_for early since it may emit code. - CodeEmitInfo* info = state_for(x, x->state()); - // in case of patching (i.e., object class is not yet loaded), we need to reexecute the instruction - // and therefore provide the state before the parameters have been consumed - CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || PatchALot) { - patching_info = state_for(x, x->state_before()); - } - - LIRItem length(x->length(), this); - length.load_item(); - - const LIR_Opr reg = result_register_for(x->type()); - LIR_Opr tmp1 = FrameMap::G1_oop_opr; - LIR_Opr tmp2 = FrameMap::G3_oop_opr; - LIR_Opr tmp3 = FrameMap::G4_oop_opr; - LIR_Opr tmp4 = FrameMap::O1_oop_opr; - LIR_Opr klass_reg = FrameMap::G5_metadata_opr; - LIR_Opr len = length.result(); - - CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info); - ciMetadata* obj = ciObjArrayKlass::make(x->klass()); - if (obj == ciEnv::unloaded_ciobjarrayklass()) { - BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error"); - } - klass2reg_with_patching(klass_reg, obj, patching_info); - __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path); - - LIR_Opr result = rlock_result(x); - __ move(reg, result); -} - - -void LIRGenerator::do_NewMultiArray(NewMultiArray* x) { - Values* dims = x->dims(); - int i = dims->length(); - LIRItemList* items = new LIRItemList(i, i, NULL); - while (i-- > 0) { - LIRItem* size = new LIRItem(dims->at(i), this); - items->at_put(i, size); - } - - // Evaluate state_for early since it may emit code. - CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || PatchALot) { - patching_info = state_for(x, x->state_before()); - - // Cannot re-use same xhandlers for multiple CodeEmitInfos, so - // clone all handlers (NOTE: Usually this is handled transparently - // by the CodeEmitInfo cloning logic in CodeStub constructors but - // is done explicitly here because a stub isn't being used). - x->set_exception_handlers(new XHandlers(x->exception_handlers())); - } - CodeEmitInfo* info = state_for(x, x->state()); - - i = dims->length(); - while (i-- > 0) { - LIRItem* size = items->at(i); - size->load_item(); - store_stack_parameter (size->result(), - in_ByteSize(STACK_BIAS + - frame::memory_parameter_word_sp_offset * wordSize + - i * sizeof(jint))); - } - - // This instruction can be deoptimized in the slow path : use - // O0 as result register. - const LIR_Opr klass_reg = FrameMap::O0_metadata_opr; - klass2reg_with_patching(klass_reg, x->klass(), patching_info); - LIR_Opr rank = FrameMap::O1_opr; - __ move(LIR_OprFact::intConst(x->rank()), rank); - LIR_Opr varargs = FrameMap::as_pointer_opr(O2); - int offset_from_sp = (frame::memory_parameter_word_sp_offset * wordSize) + STACK_BIAS; - __ add(FrameMap::SP_opr, - LIR_OprFact::intptrConst(offset_from_sp), - varargs); - LIR_OprList* args = new LIR_OprList(3); - args->append(klass_reg); - args->append(rank); - args->append(varargs); - const LIR_Opr reg = result_register_for(x->type()); - __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id), - LIR_OprFact::illegalOpr, - reg, args, info); - - LIR_Opr result = rlock_result(x); - __ move(reg, result); -} - - -void LIRGenerator::do_BlockBegin(BlockBegin* x) { -} - - -void LIRGenerator::do_CheckCast(CheckCast* x) { - LIRItem obj(x->obj(), this); - CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { - // must do this before locking the destination register as an oop register, - // and before the obj is loaded (so x->obj()->item() is valid for creating a debug info location) - patching_info = state_for(x, x->state_before()); - } - obj.load_item(); - LIR_Opr out_reg = rlock_result(x); - CodeStub* stub; - CodeEmitInfo* info_for_exception = - (x->needs_exception_state() ? state_for(x) : - state_for(x, x->state_before(), true /*ignore_xhandler*/)); - - if (x->is_incompatible_class_change_check()) { - assert(patching_info == NULL, "can't patch this"); - stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception); - } else if (x->is_invokespecial_receiver_check()) { - assert(patching_info == NULL, "can't patch this"); - stub = new DeoptimizeStub(info_for_exception, - Deoptimization::Reason_class_check, - Deoptimization::Action_none); - } else { - stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); - } - LIR_Opr tmp1 = FrameMap::G1_oop_opr; - LIR_Opr tmp2 = FrameMap::G3_oop_opr; - LIR_Opr tmp3 = FrameMap::G4_oop_opr; - __ checkcast(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, - x->direct_compare(), info_for_exception, patching_info, stub, - x->profiled_method(), x->profiled_bci()); -} - - -void LIRGenerator::do_InstanceOf(InstanceOf* x) { - LIRItem obj(x->obj(), this); - CodeEmitInfo* patching_info = NULL; - if (!x->klass()->is_loaded() || PatchALot) { - patching_info = state_for(x, x->state_before()); - } - // ensure the result register is not the input register because the result is initialized before the patching safepoint - obj.load_item(); - LIR_Opr out_reg = rlock_result(x); - LIR_Opr tmp1 = FrameMap::G1_oop_opr; - LIR_Opr tmp2 = FrameMap::G3_oop_opr; - LIR_Opr tmp3 = FrameMap::G4_oop_opr; - __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, - x->direct_compare(), patching_info, - x->profiled_method(), x->profiled_bci()); -} - - -void LIRGenerator::do_If(If* x) { - assert(x->number_of_sux() == 2, "inconsistency"); - ValueTag tag = x->x()->type()->tag(); - LIRItem xitem(x->x(), this); - LIRItem yitem(x->y(), this); - LIRItem* xin = &xitem; - LIRItem* yin = &yitem; - If::Condition cond = x->cond(); - - if (tag == longTag) { - // for longs, only conditions "eql", "neq", "lss", "geq" are valid; - // mirror for other conditions - if (cond == If::gtr || cond == If::leq) { - // swap inputs - cond = Instruction::mirror(cond); - xin = &yitem; - yin = &xitem; - } - xin->set_destroys_register(); - } - - LIR_Opr left = LIR_OprFact::illegalOpr; - LIR_Opr right = LIR_OprFact::illegalOpr; - - xin->load_item(); - left = xin->result(); - - if (is_simm13(yin->result())) { - // inline int constants which are small enough to be immediate operands - right = LIR_OprFact::value_type(yin->value()->type()); - } else if (tag == longTag && yin->is_constant() && yin->get_jlong_constant() == 0 && - (cond == If::eql || cond == If::neq)) { - // inline long zero - right = LIR_OprFact::value_type(yin->value()->type()); - } else if (tag == objectTag && yin->is_constant() && (yin->get_jobject_constant()->is_null_object())) { - right = LIR_OprFact::value_type(yin->value()->type()); - } else { - yin->load_item(); - right = yin->result(); - } - set_no_result(x); - - // add safepoint before generating condition code so it can be recomputed - if (x->is_safepoint()) { - // increment backedge counter if needed - increment_backedge_counter_conditionally(lir_cond(cond), left, right, state_for(x, x->state_before()), - x->tsux()->bci(), x->fsux()->bci(), x->profiled_bci()); - __ safepoint(safepoint_poll_register(), state_for(x, x->state_before())); - } - - __ cmp(lir_cond(cond), left, right); - // Generate branch profiling. Profiling code doesn't kill flags. - profile_branch(x, cond); - move_to_phi(x->state()); - if (x->x()->type()->is_float_kind()) { - __ branch(lir_cond(cond), right->type(), x->tsux(), x->usux()); - } else { - __ branch(lir_cond(cond), right->type(), x->tsux()); - } - assert(x->default_sux() == x->fsux(), "wrong destination above"); - __ jump(x->default_sux()); -} - - -LIR_Opr LIRGenerator::getThreadPointer() { - return FrameMap::as_pointer_opr(G2); -} - - -void LIRGenerator::trace_block_entry(BlockBegin* block) { - __ move(LIR_OprFact::intConst(block->block_id()), FrameMap::O0_opr); - LIR_OprList* args = new LIR_OprList(1); - args->append(FrameMap::O0_opr); - address func = CAST_FROM_FN_PTR(address, Runtime1::trace_block_entry); - __ call_runtime_leaf(func, rlock_callee_saved(T_INT), LIR_OprFact::illegalOpr, args); -} - - -void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, - CodeEmitInfo* info) { - __ store(value, address, info); -} - -void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, - CodeEmitInfo* info) { - __ load(address, result, info); -} diff --git a/src/hotspot/cpu/sparc/c1_LIR_sparc.cpp b/src/hotspot/cpu/sparc/c1_LIR_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_LIR_sparc.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2016, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/register.hpp" -#include "c1/c1_FrameMap.hpp" -#include "c1/c1_LIR.hpp" - -FloatRegister LIR_OprDesc::as_float_reg() const { - return FrameMap::nr2floatreg(fpu_regnr()); -} - -FloatRegister LIR_OprDesc::as_double_reg() const { - return FrameMap::nr2floatreg(fpu_regnrHi()); -} - -LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { - assert(as_FloatRegister(reg2) != fnoreg, "Sparc holds double in two regs."); - return (LIR_Opr)(intptr_t)((reg1 << LIR_OprDesc::reg1_shift) | - (reg2 << LIR_OprDesc::reg2_shift) | - LIR_OprDesc::double_type | - LIR_OprDesc::fpu_register | - LIR_OprDesc::double_size); -} - -#ifndef PRODUCT -void LIR_Address::verify() const { - assert(scale() == times_1, "Scaled addressing mode not available on SPARC and should not be used"); - assert(disp() == 0 || index()->is_illegal(), "can't have both"); - assert(base()->is_cpu_register(), "wrong base operand"); - assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand"); - assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA, - "wrong type for addresses"); -} -#endif // PRODUCT diff --git a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.cpp b/src/hotspot/cpu/sparc/c1_LinearScan_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2005, 2010, 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. - * - */ - -#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 SPARC -} diff --git a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.hpp b/src/hotspot/cpu/sparc/c1_LinearScan_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_LinearScan_sparc.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2005, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_LINEARSCAN_SPARC_HPP -#define CPU_SPARC_C1_LINEARSCAN_SPARC_HPP - -inline bool LinearScan::is_processed_reg_num(int reg_num) { - return reg_num < 26 || reg_num > 31; -} - -inline int LinearScan::num_physical_regs(BasicType type) { - // Sparc requires two cpu registers for long - // and two cpu registers for double - if (type == T_DOUBLE) { - return 2; - } - return 1; -} - - -inline bool LinearScan::requires_adjacent_regs(BasicType type) { - return type == T_DOUBLE; -} - -inline bool LinearScan::is_caller_save(int assigned_reg) { - return assigned_reg > pd_last_callee_saved_reg && assigned_reg <= pd_last_fpu_reg; -} - - -inline void LinearScan::pd_add_temps(LIR_Op* op) { - // No special case behaviours yet -} - - -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_SPARC_C1_LINEARSCAN_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.cpp +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (c) 1999, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "c1/c1_Runtime1.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc/shared/collectedHeap.hpp" -#include "interpreter/interpreter.hpp" -#include "oops/arrayOop.hpp" -#include "oops/markWord.hpp" -#include "runtime/basicLock.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/os.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" - -void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { - Label L; - const Register temp_reg = G3_scratch; - // Note: needs more testing of out-of-line vs. inline slow case - verify_oop(receiver); - load_klass(receiver, temp_reg); - cmp_and_brx_short(temp_reg, iCache, Assembler::equal, Assembler::pt, L); - AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub()); - jump_to(ic_miss, temp_reg); - delayed()->nop(); - align(CodeEntryAlignment); - bind(L); -} - - -void C1_MacroAssembler::explicit_null_check(Register base) { - Unimplemented(); -} - - -void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) { - assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); - generate_stack_overflow_check(bang_size_in_bytes); - // Create the frame. - save_frame_c1(frame_size_in_bytes); -} - - -void C1_MacroAssembler::verified_entry() { - if (C1Breakpoint) { - breakpoint_trap(); - } -} - - -void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) { - assert_different_registers(Rmark, Roop, Rbox, Rscratch); - - Label done; - - Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); - - // The following move must be the first instruction of emitted since debug - // information may be generated for it. - // Load object header - ld_ptr(mark_addr, Rmark); - - verify_oop(Roop); - - // save object being locked into the BasicObjectLock - st_ptr(Roop, Rbox, BasicObjectLock::obj_offset_in_bytes()); - - if (UseBiasedLocking) { - biased_locking_enter(Roop, Rmark, Rscratch, done, &slow_case); - } - - // Save Rbox in Rscratch to be used for the cas operation - mov(Rbox, Rscratch); - - // and mark it unlocked - or3(Rmark, markWord::unlocked_value, Rmark); - - // save unlocked object header into the displaced header location on the stack - st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes()); - - // compare object markWord with Rmark and if equal exchange Rscratch with object markWord - assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - cas_ptr(mark_addr.base(), Rmark, Rscratch); - // if compare/exchange succeeded we found an unlocked object and we now have locked it - // hence we are done - cmp(Rmark, Rscratch); - brx(Assembler::equal, false, Assembler::pt, done); - delayed()->sub(Rscratch, SP, Rscratch); //pull next instruction into delay slot - // we did not find an unlocked object so see if this is a recursive case - // sub(Rscratch, SP, Rscratch); - assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - andcc(Rscratch, 0xfffff003, Rscratch); - brx(Assembler::notZero, false, Assembler::pn, slow_case); - delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes()); - bind(done); -} - - -void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) { - assert_different_registers(Rmark, Roop, Rbox); - - Label done; - - Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); - assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - - if (UseBiasedLocking) { - // load the object out of the BasicObjectLock - ld_ptr(Rbox, BasicObjectLock::obj_offset_in_bytes(), Roop); - verify_oop(Roop); - biased_locking_exit(mark_addr, Rmark, done); - } - // Test first it it is a fast recursive unlock - ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rmark); - br_null_short(Rmark, Assembler::pt, done); - if (!UseBiasedLocking) { - // load object - ld_ptr(Rbox, BasicObjectLock::obj_offset_in_bytes(), Roop); - verify_oop(Roop); - } - - // Check if it is still a light weight lock, this is is true if we see - // the stack address of the basicLock in the markWord of the object - cas_ptr(mark_addr.base(), Rbox, Rmark); - cmp(Rbox, Rmark); - - brx(Assembler::notEqual, false, Assembler::pn, slow_case); - delayed()->nop(); - // Done - bind(done); -} - - -void C1_MacroAssembler::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, must be global register for incr_allocated_bytes - Register t2, // temp register - Label& slow_case // continuation point if fast allocation fails -) { - RegisterOrConstant size_in_bytes = var_size_in_bytes->is_valid() - ? RegisterOrConstant(var_size_in_bytes) : RegisterOrConstant(con_size_in_bytes); - if (UseTLAB) { - tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); - } else { - eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); - incr_allocated_bytes(size_in_bytes, t1, t2); - } -} - - -void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) { - assert_different_registers(obj, klass, len, t1, t2); - if (UseBiasedLocking && !len->is_valid()) { - ld_ptr(klass, in_bytes(Klass::prototype_header_offset()), t1); - } else { - set((intx)markWord::prototype().value(), t1); - } - st_ptr(t1, obj, oopDesc::mark_offset_in_bytes()); - if (UseCompressedClassPointers) { - // Save klass - mov(klass, t1); - encode_klass_not_null(t1); - stw(t1, obj, oopDesc::klass_offset_in_bytes()); - } else { - st_ptr(klass, obj, oopDesc::klass_offset_in_bytes()); - } - if (len->is_valid()) { - st(len, obj, arrayOopDesc::length_offset_in_bytes()); - } else if (UseCompressedClassPointers) { - // otherwise length is in the class gap - store_klass_gap(G0, obj); - } -} - - -void C1_MacroAssembler::initialize_body(Register base, Register index) { - zero_memory(base, index); -} - - -void C1_MacroAssembler::allocate_object( - Register obj, // result: pointer to object after successful allocation - Register t1, // temp register - Register t2, // temp register, must be a global register for try_allocate - Register t3, // temp register - int hdr_size, // object header size in words - int obj_size, // object size in words - Register klass, // object klass - Label& slow_case // continuation point if fast allocation fails -) { - assert_different_registers(obj, t1, t2, t3, klass); - assert(klass == G5, "must be G5"); - - // allocate space & initialize header - if (!is_simm13(obj_size * wordSize)) { - // would need to use extra register to load - // object size => go the slow case for now - ba(slow_case); - delayed()->nop(); - return; - } - try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case); - - initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2, /* is_tlab_allocated */ UseTLAB); -} - -void C1_MacroAssembler::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 - bool is_tlab_allocated // the object was allocated in a TLAB; relevant for the implementation of ZeroTLAB - ) { - const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize; - - initialize_header(obj, klass, noreg, t1, t2); - -#ifdef ASSERT - { - Label ok; - ld(klass, in_bytes(Klass::layout_helper_offset()), t1); - if (var_size_in_bytes != noreg) { - cmp_and_brx_short(t1, var_size_in_bytes, Assembler::equal, Assembler::pt, ok); - } else { - cmp_and_brx_short(t1, con_size_in_bytes, Assembler::equal, Assembler::pt, ok); - } - stop("bad size in initialize_object"); - should_not_reach_here(); - - bind(ok); - } - -#endif - - if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) { - // initialize body - const int threshold = 5 * HeapWordSize; // approximate break even point for code size - if (var_size_in_bytes != noreg) { - // use a loop - add(obj, hdr_size_in_bytes, t1); // compute address of first element - sub(var_size_in_bytes, hdr_size_in_bytes, t2); // compute size of body - initialize_body(t1, t2); - } else if (con_size_in_bytes <= threshold) { - // use explicit NULL stores - for (int i = hdr_size_in_bytes; i < con_size_in_bytes; i += HeapWordSize) st_ptr(G0, obj, i); - } else if (con_size_in_bytes > hdr_size_in_bytes) { - // use a loop - const Register base = t1; - const Register index = t2; - add(obj, hdr_size_in_bytes, base); // compute address of first element - // compute index = number of words to clear - set(con_size_in_bytes - hdr_size_in_bytes, index); - initialize_body(base, index); - } - } - - if (CURRENT_ENV->dtrace_alloc_probes()) { - assert(obj == O0, "must be"); - call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), - relocInfo::runtime_call_type); - delayed()->nop(); - } - - verify_oop(obj); -} - - -void C1_MacroAssembler::allocate_array( - Register obj, // result: pointer to array after successful allocation - Register len, // array length - Register t1, // temp register - Register t2, // temp register - Register t3, // temp register - int hdr_size, // object header size in words - int elt_size, // element size in bytes - Register klass, // object klass - Label& slow_case // continuation point if fast allocation fails -) { - assert_different_registers(obj, len, t1, t2, t3, klass); - assert(klass == G5, "must be G5"); - assert(t1 == G1, "must be G1"); - - // determine alignment mask - assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work"); - - // check for negative or excessive length - // note: the maximum length allowed is chosen so that arrays of any - // element size with this length are always smaller or equal - // to the largest integer (i.e., array size computation will - // not overflow) - set(max_array_allocation_length, t1); - cmp(len, t1); - br(Assembler::greaterUnsigned, false, Assembler::pn, slow_case); - - // compute array size - // note: if 0 <= len <= max_length, len*elt_size + header + alignment is - // smaller or equal to the largest integer; also, since top is always - // aligned, we can do the alignment here instead of at the end address - // computation - const Register arr_size = t1; - switch (elt_size) { - case 1: delayed()->mov(len, arr_size); break; - case 2: delayed()->sll(len, 1, arr_size); break; - case 4: delayed()->sll(len, 2, arr_size); break; - case 8: delayed()->sll(len, 3, arr_size); break; - default: ShouldNotReachHere(); - } - add(arr_size, hdr_size * wordSize + MinObjAlignmentInBytesMask, arr_size); // add space for header & alignment - and3(arr_size, ~MinObjAlignmentInBytesMask, arr_size); // align array size - - // allocate space & initialize header - if (UseTLAB) { - tlab_allocate(obj, arr_size, 0, t2, slow_case); - } else { - eden_allocate(obj, arr_size, 0, t2, t3, slow_case); - } - initialize_header(obj, klass, len, t2, t3); - - // initialize body - const Register base = t2; - const Register index = t3; - add(obj, hdr_size * wordSize, base); // compute address of first element - sub(arr_size, hdr_size * wordSize, index); // compute index = number of words to clear - initialize_body(base, index); - - if (CURRENT_ENV->dtrace_alloc_probes()) { - assert(obj == O0, "must be"); - call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), - relocInfo::runtime_call_type); - delayed()->nop(); - } - - verify_oop(obj); -} - - -#ifndef PRODUCT - -void C1_MacroAssembler::verify_stack_oop(int stack_offset) { - if (!VerifyOops) return; - verify_oop_addr(Address(SP, stack_offset + STACK_BIAS)); -} - -void C1_MacroAssembler::verify_not_null_oop(Register r) { - Label not_null; - br_notnull_short(r, Assembler::pt, not_null); - stop("non-null oop required"); - bind(not_null); - if (!VerifyOops) return; - verify_oop(r); -} - -void C1_MacroAssembler::invalidate_registers(bool iregisters, bool lregisters, bool oregisters, - Register preserve1, Register preserve2) { - if (iregisters) { - for (int i = 0; i < 6; i++) { - Register r = as_iRegister(i); - if (r != preserve1 && r != preserve2) set(0xdead, r); - } - } - if (oregisters) { - for (int i = 0; i < 6; i++) { - Register r = as_oRegister(i); - if (r != preserve1 && r != preserve2) set(0xdead, r); - } - } - if (lregisters) { - for (int i = 0; i < 8; i++) { - Register r = as_lRegister(i); - if (r != preserve1 && r != preserve2) set(0xdead, r); - } - } -} - - -#endif diff --git a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_MacroAssembler_sparc.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_MACROASSEMBLER_SPARC_HPP -#define CPU_SPARC_C1_MACROASSEMBLER_SPARC_HPP - - void pd_init() { /* nothing to do */ } - - 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 base, Register index); - - // locking/unlocking - void lock_object (Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case); - void unlock_object(Register Rmark, Register Roop, Register Rbox, 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 - bool is_tlab_allocated // the object was allocated in a TLAB; relevant for the implementation of ZeroTLAB - ); - - // 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) - void allocate_object( - Register obj, // result: pointer to object after successful allocation - Register t1, // temp register - Register t2, // temp register - Register t3, // temp register - int hdr_size, // object header size in words - int obj_size, // object size in words - Register klass, // object klass - Label& slow_case // continuation point if fast allocation fails - ); - - enum { - max_array_allocation_length = 0x01000000 // sparc friendly value, requires sethi only - }; - - // allocation of arrays - void allocate_array( - Register obj, // result: pointer to array after successful allocation - Register len, // array length - Register t1, // temp register - Register t2, // temp register - Register t3, // temp register - int hdr_size, // object header size in words - int elt_size, // element size in bytes - Register klass, // object klass - Label& slow_case // continuation point if fast allocation fails - ); - - // invalidates registers in this window - void invalidate_registers(bool iregisters, bool lregisters, bool oregisters, - Register preserve1 = noreg, Register preserve2 = noreg); - - // This platform only uses signal-based null checks. The Label is not needed. - void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); } - - void save_live_registers_no_oop_map(bool save_fpu_registers); - void restore_live_registers(bool restore_fpu_registers); - -#endif // CPU_SPARC_C1_MACROASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp +++ /dev/null @@ -1,917 +0,0 @@ -/* - * Copyright (c) 1999, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "c1/c1_Defs.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "c1/c1_Runtime1.hpp" -#include "ci/ciUtilities.hpp" -#include "gc/shared/cardTable.hpp" -#include "gc/shared/cardTableBarrierSet.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/universe.hpp" -#include "nativeInst_sparc.hpp" -#include "oops/compiledICHolder.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/signature.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/macros.hpp" -#include "utilities/align.hpp" -#include "vmreg_sparc.inline.hpp" - -// Implementation of StubAssembler - -int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry_point, int number_of_arguments) { - // for sparc changing the number of arguments doesn't change - // anything about the frame size so we'll always lie and claim that - // we are only passing 1 argument. - set_num_rt_args(1); - - assert_not_delayed(); - // bang stack before going to runtime - set(-os::vm_page_size() + STACK_BIAS, G3_scratch); - st(G0, SP, G3_scratch); - - // debugging support - assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); - - set_last_Java_frame(SP, noreg); - if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early - save_thread(L7_thread_cache); - // do the call - call(entry_point, relocInfo::runtime_call_type); - if (!VerifyThread) { - delayed()->mov(G2_thread, O0); // pass thread as first argument - } else { - delayed()->nop(); // (thread already passed) - } - int call_offset = offset(); // offset of return address - restore_thread(L7_thread_cache); - reset_last_Java_frame(); - - // check for pending exceptions - { Label L; - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - ld_ptr(exception_addr, Gtemp); - br_null_short(Gtemp, pt, L); - Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); - st_ptr(G0, vm_result_addr); - Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); - st_ptr(G0, vm_result_addr_2); - - if (frame_size() == no_frame_size) { - // we use O7 linkage so that forward_exception_entry has the issuing PC - call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - delayed()->restore(); - } else if (_stub_id == Runtime1::forward_exception_id) { - should_not_reach_here(); - } else { - AddressLiteral exc(Runtime1::entry_for(Runtime1::forward_exception_id)); - jump_to(exc, G4); - delayed()->nop(); - } - bind(L); - } - - // get oop result if there is one and reset the value in the thread - if (oop_result1->is_valid()) { // get oop result if there is one and reset it in the thread - get_vm_result (oop_result1); - } else { - // be a little paranoid and clear the result - Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); - st_ptr(G0, vm_result_addr); - } - - // get second result if there is one and reset the value in the thread - if (metadata_result->is_valid()) { - get_vm_result_2 (metadata_result); - } else { - // be a little paranoid and clear the result - Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); - st_ptr(G0, vm_result_addr_2); - } - - return call_offset; -} - - -int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { - // O0 is reserved for the thread - mov(arg1, O1); - return call_RT(oop_result1, metadata_result, entry, 1); -} - - -int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) { - // O0 is reserved for the thread - mov(arg1, O1); - mov(arg2, O2); assert(arg2 != O1, "smashed argument"); - return call_RT(oop_result1, metadata_result, entry, 2); -} - - -int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { - // O0 is reserved for the thread - mov(arg1, O1); - mov(arg2, O2); assert(arg2 != O1, "smashed argument"); - mov(arg3, O3); assert(arg3 != O1 && arg3 != O2, "smashed argument"); - return call_RT(oop_result1, metadata_result, entry, 3); -} - -void StubAssembler::prologue(const char* name, bool must_gc_arguments) { - set_info(name, must_gc_arguments); -} - -void StubAssembler::epilogue() { - delayed()->restore(); -} - -// Implementation of Runtime1 - - -static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs]; -static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs]; -static int reg_save_size_in_words; -static int frame_size_in_bytes = -1; - -static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { - assert(frame_size_in_bytes == sasm->total_frame_size_in_bytes(reg_save_size_in_words), - "mismatch in calculation"); - sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); - int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); - OopMap* oop_map = new OopMap(frame_size_in_slots, 0); - - int i; - for (i = 0; i < FrameMap::nof_cpu_regs; i++) { - Register r = as_Register(i); - if (r == G1 || r == G3 || r == G4 || r == G5) { - int sp_offset = cpu_reg_save_offsets[i]; - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), - r->as_VMReg()); - } - } - - if (save_fpu_registers) { - for (i = 0; i < FrameMap::nof_fpu_regs; i++) { - FloatRegister r = as_FloatRegister(i); - int sp_offset = fpu_reg_save_offsets[i]; - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), - r->as_VMReg()); - } - } - return oop_map; -} - -#define __ this-> - -void C1_MacroAssembler::save_live_registers_no_oop_map(bool save_fpu_registers) { - assert(frame_size_in_bytes == __ total_frame_size_in_bytes(reg_save_size_in_words), - "mismatch in calculation"); - __ save_frame_c1(frame_size_in_bytes); - - // Record volatile registers as callee-save values in an OopMap so their save locations will be - // propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for - // deoptimization; see compiledVFrame::create_stack_value). The caller's I, L and O registers - // are saved in register windows - I's and L's in the caller's frame and O's in the stub frame - // (as the stub's I's) when the runtime routine called by the stub creates its frame. - // OopMap frame sizes are in c2 stack slot sizes (sizeof(jint)) - - int i; - for (i = 0; i < FrameMap::nof_cpu_regs; i++) { - Register r = as_Register(i); - if (r == G1 || r == G3 || r == G4 || r == G5) { - int sp_offset = cpu_reg_save_offsets[i]; - __ st_ptr(r, SP, (sp_offset * BytesPerWord) + STACK_BIAS); - } - } - - if (save_fpu_registers) { - for (i = 0; i < FrameMap::nof_fpu_regs; i++) { - FloatRegister r = as_FloatRegister(i); - int sp_offset = fpu_reg_save_offsets[i]; - __ stf(FloatRegisterImpl::S, r, SP, (sp_offset * BytesPerWord) + STACK_BIAS); - } - } -} - -void C1_MacroAssembler::restore_live_registers(bool restore_fpu_registers) { - for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { - Register r = as_Register(i); - if (r == G1 || r == G3 || r == G4 || r == G5) { - __ ld_ptr(SP, (cpu_reg_save_offsets[i] * BytesPerWord) + STACK_BIAS, r); - } - } - - if (restore_fpu_registers) { - for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { - FloatRegister r = as_FloatRegister(i); - __ ldf(FloatRegisterImpl::S, SP, (fpu_reg_save_offsets[i] * BytesPerWord) + STACK_BIAS, r); - } - } -} - -#undef __ -#define __ sasm-> - -static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true) { - __ save_live_registers_no_oop_map(save_fpu_registers); - return generate_oop_map(sasm, save_fpu_registers); -} - -static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { - __ restore_live_registers(restore_fpu_registers); -} - - -void Runtime1::initialize_pd() { - // compute word offsets from SP at which live (non-windowed) registers are captured by stub routines - // - // A stub routine will have a frame that is at least large enough to hold - // a register window save area (obviously) and the volatile g registers - // and floating registers. A user of save_live_registers can have a frame - // that has more scratch area in it (although typically they will use L-regs). - // in that case the frame will look like this (stack growing down) - // - // FP -> | | - // | scratch mem | - // | " " | - // -------------- - // | float regs | - // | " " | - // --------------- - // | G regs | - // | " " | - // --------------- - // | abi reg. | - // | window save | - // | area | - // SP -> --------------- - // - int i; - int sp_offset = align_up((int)frame::register_save_words, 2); // start doubleword aligned - - // only G int registers are saved explicitly; others are found in register windows - for (i = 0; i < FrameMap::nof_cpu_regs; i++) { - Register r = as_Register(i); - if (r == G1 || r == G3 || r == G4 || r == G5) { - cpu_reg_save_offsets[i] = sp_offset; - sp_offset++; - } - } - - // all float registers are saved explicitly - assert(FrameMap::nof_fpu_regs == 32, "double registers not handled here"); - for (i = 0; i < FrameMap::nof_fpu_regs; i++) { - fpu_reg_save_offsets[i] = sp_offset; - sp_offset++; - } - reg_save_size_in_words = sp_offset - frame::memory_parameter_word_sp_offset; - // this should match assembler::total_frame_size_in_bytes, which - // isn't callable from this context. It's checked by an assert when - // it's used though. - frame_size_in_bytes = align_up(sp_offset * wordSize, 8); -} - - -OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { - // make a frame and preserve the caller's caller-save registers - OopMap* oop_map = save_live_registers(sasm); - int call_offset; - if (!has_argument) { - call_offset = __ call_RT(noreg, noreg, target); - } else { - call_offset = __ call_RT(noreg, noreg, target, G4, G5); - } - OopMapSet* oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - - __ should_not_reach_here(); - return oop_maps; -} - - -OopMapSet* Runtime1::generate_stub_call(StubAssembler* sasm, Register result, address target, - Register arg1, Register arg2, Register arg3) { - // make a frame and preserve the caller's caller-save registers - OopMap* oop_map = save_live_registers(sasm); - - int call_offset; - if (arg1 == noreg) { - call_offset = __ call_RT(result, noreg, target); - } else if (arg2 == noreg) { - call_offset = __ call_RT(result, noreg, target, arg1); - } else if (arg3 == noreg) { - call_offset = __ call_RT(result, noreg, target, arg1, arg2); - } else { - call_offset = __ call_RT(result, noreg, target, arg1, arg2, arg3); - } - OopMapSet* oop_maps = NULL; - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - - __ ret(); - __ delayed()->restore(); - - return oop_maps; -} - - -OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { - // make a frame and preserve the caller's caller-save registers - OopMap* oop_map = save_live_registers(sasm); - - // call the runtime patching routine, returns non-zero if nmethod got deopted. - int call_offset = __ call_RT(noreg, noreg, target); - OopMapSet* oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - - // re-execute the patched instruction or, if the nmethod was deoptmized, return to the - // deoptimization handler entry that will cause re-execution of the current bytecode - DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); - assert(deopt_blob != NULL, "deoptimization blob must have been created"); - - Label no_deopt; - __ br_null_short(O0, Assembler::pt, no_deopt); - - // return to the deoptimization handler entry for unpacking and rexecute - // if we simply returned the we'd deopt as if any call we patched had just - // returned. - - restore_live_registers(sasm); - - AddressLiteral dest(deopt_blob->unpack_with_reexecution()); - __ jump_to(dest, O0); - __ delayed()->restore(); - - __ bind(no_deopt); - restore_live_registers(sasm); - __ ret(); - __ delayed()->restore(); - - return oop_maps; -} - -OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { - - OopMapSet* oop_maps = NULL; - // for better readability - const bool must_gc_arguments = true; - const bool dont_gc_arguments = false; - - // stub code & info for the different stubs - switch (id) { - case forward_exception_id: - { - oop_maps = generate_handle_exception(id, sasm); - } - break; - - case new_instance_id: - case fast_new_instance_id: - case fast_new_instance_init_check_id: - { - Register G5_klass = G5; // Incoming - Register O0_obj = O0; // Outgoing - - if (id == new_instance_id) { - __ set_info("new_instance", dont_gc_arguments); - } else if (id == fast_new_instance_id) { - __ set_info("fast new_instance", dont_gc_arguments); - } else { - assert(id == fast_new_instance_init_check_id, "bad StubID"); - __ set_info("fast new_instance init check", dont_gc_arguments); - } - - // If TLAB is disabled, see if there is support for inlining contiguous - // allocations. - // Otherwise, just go to the slow path. - if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) && - !UseTLAB && Universe::heap()->supports_inline_contig_alloc()) { - Label slow_path; - Register G1_obj_size = G1; - Register G3_t1 = G3; - Register G4_t2 = G4; - assert_different_registers(G5_klass, G1_obj_size, G3_t1, G4_t2); - - // Push a frame since we may do dtrace notification for the - // allocation which requires calling out and we don't want - // to stomp the real return address. - __ save_frame(0); - - if (id == fast_new_instance_init_check_id) { - // make sure the klass is initialized - __ ldub(G5_klass, in_bytes(InstanceKlass::init_state_offset()), G3_t1); - __ cmp(G3_t1, InstanceKlass::fully_initialized); - __ br(Assembler::notEqual, false, Assembler::pn, slow_path); - __ delayed()->nop(); - } -#ifdef ASSERT - // assert object can be fast path allocated - { - Label ok, not_ok; - __ ld(G5_klass, in_bytes(Klass::layout_helper_offset()), G1_obj_size); - // make sure it's an instance (LH > 0) - __ cmp_and_br_short(G1_obj_size, 0, Assembler::lessEqual, Assembler::pn, not_ok); - __ btst(Klass::_lh_instance_slow_path_bit, G1_obj_size); - __ br(Assembler::zero, false, Assembler::pn, ok); - __ delayed()->nop(); - __ bind(not_ok); - __ stop("assert(can be fast path allocated)"); - __ should_not_reach_here(); - __ bind(ok); - } -#endif // ASSERT - - // If we got here then the TLAB allocation failed, so try allocating directly from eden. - // get the instance size - __ ld(G5_klass, in_bytes(Klass::layout_helper_offset()), G1_obj_size); - __ eden_allocate(O0_obj, G1_obj_size, 0, G3_t1, G4_t2, slow_path); - __ incr_allocated_bytes(G1_obj_size, G3_t1, G4_t2); - - __ initialize_object(O0_obj, G5_klass, G1_obj_size, 0, G3_t1, G4_t2, /* is_tlab_allocated */ false); - __ verify_oop(O0_obj); - __ mov(O0, I0); - __ ret(); - __ delayed()->restore(); - - __ bind(slow_path); - - // pop this frame so generate_stub_call can push it's own - __ restore(); - } - - oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_instance), G5_klass); - // I0->O0: new instance - } - - break; - - case counter_overflow_id: - // G4 contains bci, G5 contains method - oop_maps = generate_stub_call(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), G4, G5); - break; - - case new_type_array_id: - case new_object_array_id: - { - Register G5_klass = G5; // Incoming - Register G4_length = G4; // Incoming - Register O0_obj = O0; // Outgoing - - Address klass_lh(G5_klass, Klass::layout_helper_offset()); - assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise"); - assert(Klass::_lh_header_size_mask == 0xFF, "bytewise"); - // Use this offset to pick out an individual byte of the layout_helper: - const int klass_lh_header_size_offset = ((BytesPerInt - 1) // 3 - 2 selects byte {0,1,0,0} - - Klass::_lh_header_size_shift / BitsPerByte); - - if (id == new_type_array_id) { - __ set_info("new_type_array", dont_gc_arguments); - } else { - __ set_info("new_object_array", dont_gc_arguments); - } - -#ifdef ASSERT - // assert object type is really an array of the proper kind - { - Label ok; - Register G3_t1 = G3; - __ ld(klass_lh, G3_t1); - __ sra(G3_t1, Klass::_lh_array_tag_shift, G3_t1); - int tag = ((id == new_type_array_id) - ? Klass::_lh_array_tag_type_value - : Klass::_lh_array_tag_obj_value); - __ cmp_and_brx_short(G3_t1, tag, Assembler::equal, Assembler::pt, ok); - __ stop("assert(is an array klass)"); - __ should_not_reach_here(); - __ bind(ok); - } -#endif // ASSERT - - if (id == new_type_array_id) { - oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_type_array), G5_klass, G4_length); - } else { - oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_object_array), G5_klass, G4_length); - } - // I0 -> O0: new array - } - break; - - case new_multi_array_id: - { // O0: klass - // O1: rank - // O2: address of 1st dimension - __ set_info("new_multi_array", dont_gc_arguments); - oop_maps = generate_stub_call(sasm, I0, CAST_FROM_FN_PTR(address, new_multi_array), I0, I1, I2); - // I0 -> O0: new multi array - } - break; - - case register_finalizer_id: - { - __ set_info("register_finalizer", dont_gc_arguments); - - // load the klass and check the has finalizer flag - Label register_finalizer; - Register t = O1; - __ load_klass(O0, t); - __ ld(t, in_bytes(Klass::access_flags_offset()), t); - __ set(JVM_ACC_HAS_FINALIZER, G3); - __ andcc(G3, t, G0); - __ br(Assembler::notZero, false, Assembler::pt, register_finalizer); - __ delayed()->nop(); - - // do a leaf return - __ retl(); - __ delayed()->nop(); - - __ bind(register_finalizer); - OopMap* oop_map = save_live_registers(sasm); - int call_offset = __ call_RT(noreg, noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), I0); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - - // Now restore all the live registers - restore_live_registers(sasm); - - __ ret(); - __ delayed()->restore(); - } - break; - - case throw_range_check_failed_id: - { __ set_info("range_check_failed", dont_gc_arguments); // arguments will be discarded - // G4: index - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true); - } - break; - - case throw_index_exception_id: - { __ set_info("index_range_check_failed", dont_gc_arguments); // arguments will be discarded - // G4: index - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true); - } - break; - - case throw_div0_exception_id: - { __ set_info("throw_div0_exception", dont_gc_arguments); - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); - } - break; - - case throw_null_pointer_exception_id: - { __ set_info("throw_null_pointer_exception", dont_gc_arguments); - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); - } - break; - - case handle_exception_id: - { __ set_info("handle_exception", dont_gc_arguments); - oop_maps = generate_handle_exception(id, sasm); - } - break; - - case handle_exception_from_callee_id: - { __ set_info("handle_exception_from_callee", dont_gc_arguments); - oop_maps = generate_handle_exception(id, sasm); - } - break; - - case unwind_exception_id: - { - // O0: exception - // I7: address of call to this method - - __ set_info("unwind_exception", dont_gc_arguments); - __ mov(Oexception, Oexception->after_save()); - __ add(I7, frame::pc_return_offset, Oissuing_pc->after_save()); - - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - G2_thread, Oissuing_pc->after_save()); - __ verify_not_null_oop(Oexception->after_save()); - - // Restore SP from L7 if the exception PC is a method handle call site. - __ mov(O0, G5); // Save the target address. - __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0); - __ tst(L0); // Condition codes are preserved over the restore. - __ restore(); - - __ jmp(G5, 0); - __ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required. - } - break; - - case throw_array_store_exception_id: - { - __ set_info("throw_array_store_exception", dont_gc_arguments); - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true); - } - break; - - case throw_class_cast_exception_id: - { - // G4: object - __ set_info("throw_class_cast_exception", dont_gc_arguments); - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true); - } - break; - - case throw_incompatible_class_change_error_id: - { - __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments); - oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false); - } - break; - - case slow_subtype_check_id: - { // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super ); - // Arguments : - // - // ret : G3 - // sub : G3, argument, destroyed - // super: G1, argument, not changed - // raddr: O7, blown by call - Label miss; - - __ save_frame(0); // Blow no registers! - - __ check_klass_subtype_slow_path(G3, G1, L0, L1, L2, L4, NULL, &miss); - - __ mov(1, G3); - __ ret(); // Result in G5 is 'true' - __ delayed()->restore(); // free copy or add can go here - - __ bind(miss); - __ mov(0, G3); - __ ret(); // Result in G5 is 'false' - __ delayed()->restore(); // free copy or add can go here - } - - case monitorenter_nofpu_id: - case monitorenter_id: - { // G4: object - // G5: lock address - __ set_info("monitorenter", dont_gc_arguments); - - int save_fpu_registers = (id == monitorenter_id); - // make a frame and preserve the caller's caller-save registers - OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); - - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), G4, G5); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm, save_fpu_registers); - - __ ret(); - __ delayed()->restore(); - } - break; - - case monitorexit_nofpu_id: - case monitorexit_id: - { // G4: lock address - // note: really a leaf routine but must setup last java sp - // => use call_RT for now (speed can be improved by - // doing last java sp setup manually) - __ set_info("monitorexit", dont_gc_arguments); - - int save_fpu_registers = (id == monitorexit_id); - // make a frame and preserve the caller's caller-save registers - OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); - - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), G4); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm, save_fpu_registers); - - __ ret(); - __ delayed()->restore(); - } - break; - - case deoptimize_id: - { - __ set_info("deoptimize", dont_gc_arguments); - OopMap* oop_map = save_live_registers(sasm); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize), G4); - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - restore_live_registers(sasm); - DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); - assert(deopt_blob != NULL, "deoptimization blob must have been created"); - AddressLiteral dest(deopt_blob->unpack_with_reexecution()); - __ jump_to(dest, O0); - __ delayed()->restore(); - } - break; - - case access_field_patching_id: - { __ set_info("access_field_patching", dont_gc_arguments); - oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); - } - break; - - case load_klass_patching_id: - { __ set_info("load_klass_patching", dont_gc_arguments); - oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)); - } - break; - - case load_mirror_patching_id: - { __ set_info("load_mirror_patching", dont_gc_arguments); - oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching)); - } - break; - - case load_appendix_patching_id: - { __ set_info("load_appendix_patching", dont_gc_arguments); - oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching)); - } - break; - - case dtrace_object_alloc_id: - { // O0: object - __ set_info("dtrace_object_alloc", dont_gc_arguments); - // we can't gc here so skip the oopmap but make sure that all - // the live registers get saved. - save_live_registers(sasm); - - __ save_thread(L7_thread_cache); - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), - relocInfo::runtime_call_type); - __ delayed()->mov(I0, O0); - __ restore_thread(L7_thread_cache); - - restore_live_registers(sasm); - __ ret(); - __ delayed()->restore(); - } - break; - - case predicate_failed_trap_id: - { - __ set_info("predicate_failed_trap", dont_gc_arguments); - OopMap* oop_map = save_live_registers(sasm); - - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)); - - oop_maps = new OopMapSet(); - oop_maps->add_gc_map(call_offset, oop_map); - - DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); - assert(deopt_blob != NULL, "deoptimization blob must have been created"); - restore_live_registers(sasm); - - AddressLiteral dest(deopt_blob->unpack_with_reexecution()); - __ jump_to(dest, O0); - __ delayed()->restore(); - } - break; - - default: - { __ set_info("unimplemented entry", dont_gc_arguments); - __ save_frame(0); - __ set((int)id, O1); - __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), O1); - __ should_not_reach_here(); - } - break; - } - return oop_maps; -} - - -OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) { - __ block_comment("generate_handle_exception"); - - // Save registers, if required. - OopMapSet* oop_maps = new OopMapSet(); - OopMap* oop_map = NULL; - switch (id) { - case forward_exception_id: - // We're handling an exception in the context of a compiled frame. - // The registers have been saved in the standard places. Perform - // an exception lookup in the caller and dispatch to the handler - // if found. Otherwise unwind and dispatch to the callers - // exception handler. - oop_map = generate_oop_map(sasm, true); - - // transfer the pending exception to the exception_oop - __ ld_ptr(G2_thread, in_bytes(JavaThread::pending_exception_offset()), Oexception); - __ ld_ptr(Oexception, 0, G0); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::pending_exception_offset())); - __ add(I7, frame::pc_return_offset, Oissuing_pc); - break; - case handle_exception_id: - // At this point all registers MAY be live. - oop_map = save_live_registers(sasm); - __ mov(Oexception->after_save(), Oexception); - __ mov(Oissuing_pc->after_save(), Oissuing_pc); - break; - case handle_exception_from_callee_id: - // At this point all registers except exception oop (Oexception) - // and exception pc (Oissuing_pc) are dead. - oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); - sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); - __ save_frame_c1(frame_size_in_bytes); - __ mov(Oexception->after_save(), Oexception); - __ mov(Oissuing_pc->after_save(), Oissuing_pc); - break; - default: ShouldNotReachHere(); - } - - __ verify_not_null_oop(Oexception); - -#ifdef ASSERT - // check that fields in JavaThread for exception oop and issuing pc are - // empty before writing to them - Label oop_empty; - Register scratch = I7; // We can use I7 here because it's overwritten later anyway. - __ ld_ptr(Address(G2_thread, JavaThread::exception_oop_offset()), scratch); - __ br_null(scratch, false, Assembler::pt, oop_empty); - __ delayed()->nop(); - __ stop("exception oop already set"); - __ bind(oop_empty); - - Label pc_empty; - __ ld_ptr(Address(G2_thread, JavaThread::exception_pc_offset()), scratch); - __ br_null(scratch, false, Assembler::pt, pc_empty); - __ delayed()->nop(); - __ stop("exception pc already set"); - __ bind(pc_empty); -#endif - - // save the exception and issuing pc in the thread - __ st_ptr(Oexception, G2_thread, in_bytes(JavaThread::exception_oop_offset())); - __ st_ptr(Oissuing_pc, G2_thread, in_bytes(JavaThread::exception_pc_offset())); - - // use the throwing pc as the return address to lookup (has bci & oop map) - __ mov(Oissuing_pc, I7); - __ sub(I7, frame::pc_return_offset, I7); - int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); - oop_maps->add_gc_map(call_offset, oop_map); - - // Note: if nmethod has been deoptimized then regardless of - // whether it had a handler or not we will deoptimize - // by entering the deopt blob with a pending exception. - - // Restore the registers that were saved at the beginning, remove - // the frame and jump to the exception handler. - switch (id) { - case forward_exception_id: - case handle_exception_id: - restore_live_registers(sasm); - __ jmp(O0, 0); - __ delayed()->restore(); - break; - case handle_exception_from_callee_id: - // Restore SP from L7 if the exception PC is a method handle call site. - __ mov(O0, G5); // Save the target address. - __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), L0); - __ tst(L0); // Condition codes are preserved over the restore. - __ restore(); - - __ jmp(G5, 0); // jump to the exception handler - __ delayed()->movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); // Restore SP if required. - break; - default: ShouldNotReachHere(); - } - - return oop_maps; -} - - -#undef __ - -const char *Runtime1::pd_name_for_address(address entry) { - return ""; -} diff --git a/src/hotspot/cpu/sparc/c1_globals_sparc.hpp b/src/hotspot/cpu/sparc/c1_globals_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c1_globals_sparc.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C1_GLOBALS_SPARC_HPP -#define CPU_SPARC_C1_GLOBALS_SPARC_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, CICompileOSR, 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); -define_pd_global(intx, CompileThreshold, 1000 ); // Design center runs on 1.3.1 - -define_pd_global(intx, OnStackReplacePercentage, 1400 ); -define_pd_global(bool, UseTLAB, true ); -define_pd_global(bool, ProfileInterpreter, false); -define_pd_global(intx, FreqInlineSize, 325 ); -define_pd_global(bool, ResizeTLAB, true ); -define_pd_global(uintx, ReservedCodeCacheSize, 32*M ); -define_pd_global(uintx, NonProfiledCodeHeapSize, 13*M ); -define_pd_global(uintx, ProfiledCodeHeapSize, 14*M ); -define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M ); -define_pd_global(uintx, CodeCacheExpansionSize, 32*K ); -define_pd_global(uintx, CodeCacheMinBlockLength, 1); -define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); -define_pd_global(size_t, MetaspaceSize, 12*M ); -define_pd_global(bool, NeverActAsServerClassMachine, true ); -define_pd_global(size_t, NewSizeThreadIncrease, 16*K ); -define_pd_global(uint64_t, MaxRAM, 1ULL*G); -define_pd_global(uintx, InitialCodeCacheSize, 160*K); -#endif // !TIERED - -define_pd_global(bool, UseTypeProfile, false); - -define_pd_global(bool, LIRFillDelaySlots, true ); -define_pd_global(bool, OptimizeSinglePrecision, false); -define_pd_global(bool, CSEArrayLength, true ); -define_pd_global(bool, TwoOperandLIRForm, false); - -#endif // CPU_SPARC_C1_GLOBALS_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (c) 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/assembler.hpp" -#include "asm/assembler.inline.hpp" -#include "oops/arrayOop.hpp" -#include "opto/c2_MacroAssembler.hpp" -#include "opto/intrinsicnode.hpp" - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) /* nothing */ -#define STOP(error) stop(error) -#else -#define BLOCK_COMMENT(str) block_comment(str) -#define STOP(error) block_comment(error); stop(error) -#endif - -// Compress char[] to byte[] by compressing 16 bytes at once. Return 0 on failure. -void C2_MacroAssembler::string_compress_16(Register src, Register dst, Register cnt, Register result, - Register tmp1, Register tmp2, Register tmp3, Register tmp4, - FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, Label& Ldone) { - Label Lloop, Lslow; - assert(UseVIS >= 3, "VIS3 is required"); - assert_different_registers(src, dst, cnt, tmp1, tmp2, tmp3, tmp4, result); - assert_different_registers(ftmp1, ftmp2, ftmp3); - - // Check if cnt >= 8 (= 16 bytes) - cmp(cnt, 8); - br(Assembler::less, false, Assembler::pn, Lslow); - delayed()->mov(cnt, result); // copy count - - // Check for 8-byte alignment of src and dst - or3(src, dst, tmp1); - andcc(tmp1, 7, G0); - br(Assembler::notZero, false, Assembler::pn, Lslow); - delayed()->nop(); - - // Set mask for bshuffle instruction - Register mask = tmp4; - set(0x13579bdf, mask); - bmask(mask, G0, G0); - - // Set mask to 0xff00 ff00 ff00 ff00 to check for non-latin1 characters - Assembler::sethi(0xff00fc00, mask); // mask = 0x0000 0000 ff00 fc00 - add(mask, 0x300, mask); // mask = 0x0000 0000 ff00 ff00 - sllx(mask, 32, tmp1); // tmp1 = 0xff00 ff00 0000 0000 - or3(mask, tmp1, mask); // mask = 0xff00 ff00 ff00 ff00 - - // Load first 8 bytes - ldx(src, 0, tmp1); - - bind(Lloop); - // Load next 8 bytes - ldx(src, 8, tmp2); - - // Check for non-latin1 character by testing if the most significant byte of a char is set. - // Although we have to move the data between integer and floating point registers, this is - // still faster than the corresponding VIS instructions (ford/fand/fcmpd). - or3(tmp1, tmp2, tmp3); - btst(tmp3, mask); - // annul zeroing if branch is not taken to preserve original count - brx(Assembler::notZero, true, Assembler::pn, Ldone); - delayed()->mov(G0, result); // 0 - failed - - // Move bytes into float register - movxtod(tmp1, ftmp1); - movxtod(tmp2, ftmp2); - - // Compress by copying one byte per char from ftmp1 and ftmp2 to ftmp3 - bshuffle(ftmp1, ftmp2, ftmp3); - stf(FloatRegisterImpl::D, ftmp3, dst, 0); - - // Increment addresses and decrement count - inc(src, 16); - inc(dst, 8); - dec(cnt, 8); - - cmp(cnt, 8); - // annul LDX if branch is not taken to prevent access past end of string - br(Assembler::greaterEqual, true, Assembler::pt, Lloop); - delayed()->ldx(src, 0, tmp1); - - // Fallback to slow version - bind(Lslow); -} - -// Compress char[] to byte[]. Return 0 on failure. -void C2_MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register result, Register tmp, Label& Ldone) { - Label Lloop; - assert_different_registers(src, dst, cnt, tmp, result); - - lduh(src, 0, tmp); - - bind(Lloop); - inc(src, sizeof(jchar)); - cmp(tmp, 0xff); - // annul zeroing if branch is not taken to preserve original count - br(Assembler::greater, true, Assembler::pn, Ldone); // don't check xcc - delayed()->mov(G0, result); // 0 - failed - deccc(cnt); - stb(tmp, dst, 0); - inc(dst); - // annul LDUH if branch is not taken to prevent access past end of string - br(Assembler::notZero, true, Assembler::pt, Lloop); - delayed()->lduh(src, 0, tmp); // hoisted -} - -// Inflate byte[] to char[] by inflating 16 bytes at once. -void C2_MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt, Register tmp, - FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, FloatRegister ftmp4, Label& Ldone) { - Label Lloop, Lslow; - assert(UseVIS >= 3, "VIS3 is required"); - assert_different_registers(src, dst, cnt, tmp); - assert_different_registers(ftmp1, ftmp2, ftmp3, ftmp4); - - // Check if cnt >= 8 (= 16 bytes) - cmp(cnt, 8); - br(Assembler::less, false, Assembler::pn, Lslow); - delayed()->nop(); - - // Check for 8-byte alignment of src and dst - or3(src, dst, tmp); - andcc(tmp, 7, G0); - br(Assembler::notZero, false, Assembler::pn, Lslow); - // Initialize float register to zero - FloatRegister zerof = ftmp4; - delayed()->fzero(FloatRegisterImpl::D, zerof); - - // Load first 8 bytes - ldf(FloatRegisterImpl::D, src, 0, ftmp1); - - bind(Lloop); - inc(src, 8); - dec(cnt, 8); - - // Inflate the string by interleaving each byte from the source array - // with a zero byte and storing the result in the destination array. - fpmerge(zerof, ftmp1->successor(), ftmp2); - stf(FloatRegisterImpl::D, ftmp2, dst, 8); - fpmerge(zerof, ftmp1, ftmp3); - stf(FloatRegisterImpl::D, ftmp3, dst, 0); - - inc(dst, 16); - - cmp(cnt, 8); - // annul LDX if branch is not taken to prevent access past end of string - br(Assembler::greaterEqual, true, Assembler::pt, Lloop); - delayed()->ldf(FloatRegisterImpl::D, src, 0, ftmp1); - - // Fallback to slow version - bind(Lslow); -} - -// Inflate byte[] to char[]. -void C2_MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp, Label& Ldone) { - Label Loop; - assert_different_registers(src, dst, cnt, tmp); - - ldub(src, 0, tmp); - bind(Loop); - inc(src); - deccc(cnt); - sth(tmp, dst, 0); - inc(dst, sizeof(jchar)); - // annul LDUB if branch is not taken to prevent access past end of string - br(Assembler::notZero, true, Assembler::pt, Loop); - delayed()->ldub(src, 0, tmp); // hoisted -} - -void C2_MacroAssembler::string_compare(Register str1, Register str2, - Register cnt1, Register cnt2, - Register tmp1, Register tmp2, - Register result, int ae) { - Label Ldone, Lloop; - assert_different_registers(str1, str2, cnt1, cnt2, tmp1, result); - int stride1, stride2; - - // Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a) - // we interchange str1 and str2 in the UL case and negate the result. - // Like this, str1 is always latin1 encoded, expect for the UU case. - - if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { - srl(cnt2, 1, cnt2); - } - - // See if the lengths are different, and calculate min in cnt1. - // Save diff in case we need it for a tie-breaker. - Label Lskip; - Register diff = tmp1; - subcc(cnt1, cnt2, diff); - br(Assembler::greater, true, Assembler::pt, Lskip); - // cnt2 is shorter, so use its count: - delayed()->mov(cnt2, cnt1); - bind(Lskip); - - // Rename registers - Register limit1 = cnt1; - Register limit2 = limit1; - Register chr1 = result; - Register chr2 = cnt2; - if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { - // We need an additional register to keep track of two limits - assert_different_registers(str1, str2, cnt1, cnt2, tmp1, tmp2, result); - limit2 = tmp2; - } - - // Is the minimum length zero? - cmp(limit1, (int)0); // use cast to resolve overloading ambiguity - br(Assembler::equal, true, Assembler::pn, Ldone); - // result is difference in lengths - if (ae == StrIntrinsicNode::UU) { - delayed()->sra(diff, 1, result); // Divide by 2 to get number of chars - } else { - delayed()->mov(diff, result); - } - - // Load first characters - if (ae == StrIntrinsicNode::LL) { - stride1 = stride2 = sizeof(jbyte); - ldub(str1, 0, chr1); - ldub(str2, 0, chr2); - } else if (ae == StrIntrinsicNode::UU) { - stride1 = stride2 = sizeof(jchar); - lduh(str1, 0, chr1); - lduh(str2, 0, chr2); - } else { - stride1 = sizeof(jbyte); - stride2 = sizeof(jchar); - ldub(str1, 0, chr1); - lduh(str2, 0, chr2); - } - - // Compare first characters - subcc(chr1, chr2, chr1); - br(Assembler::notZero, false, Assembler::pt, Ldone); - assert(chr1 == result, "result must be pre-placed"); - delayed()->nop(); - - // Check if the strings start at same location - cmp(str1, str2); - brx(Assembler::equal, true, Assembler::pn, Ldone); - delayed()->mov(G0, result); // result is zero - - // We have no guarantee that on 64 bit the higher half of limit is 0 - signx(limit1); - - // Get limit - if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { - sll(limit1, 1, limit2); - subcc(limit2, stride2, chr2); - } - subcc(limit1, stride1, chr1); - br(Assembler::zero, true, Assembler::pn, Ldone); - // result is difference in lengths - if (ae == StrIntrinsicNode::UU) { - delayed()->sra(diff, 1, result); // Divide by 2 to get number of chars - } else { - delayed()->mov(diff, result); - } - - // Shift str1 and str2 to the end of the arrays, negate limit - add(str1, limit1, str1); - add(str2, limit2, str2); - neg(chr1, limit1); // limit1 = -(limit1-stride1) - if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { - neg(chr2, limit2); // limit2 = -(limit2-stride2) - } - - // Compare the rest of the characters - load_sized_value(Address(str1, limit1), chr1, (ae == StrIntrinsicNode::UU) ? 2 : 1, false); - - bind(Lloop); - load_sized_value(Address(str2, limit2), chr2, (ae == StrIntrinsicNode::LL) ? 1 : 2, false); - - subcc(chr1, chr2, chr1); - br(Assembler::notZero, false, Assembler::pt, Ldone); - assert(chr1 == result, "result must be pre-placed"); - delayed()->inccc(limit1, stride1); - if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { - inccc(limit2, stride2); - } - - // annul LDUB if branch is not taken to prevent access past end of string - br(Assembler::notZero, true, Assembler::pt, Lloop); - delayed()->load_sized_value(Address(str1, limit1), chr1, (ae == StrIntrinsicNode::UU) ? 2 : 1, false); - - // If strings are equal up to min length, return the length difference. - if (ae == StrIntrinsicNode::UU) { - // Divide by 2 to get number of chars - sra(diff, 1, result); - } else { - mov(diff, result); - } - - // Otherwise, return the difference between the first mismatched chars. - bind(Ldone); - if(ae == StrIntrinsicNode::UL) { - // Negate result (see note above) - neg(result); - } -} - -void C2_MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2, - Register limit, Register tmp, Register result, bool is_byte) { - Label Ldone, Lloop, Lremaining; - assert_different_registers(ary1, ary2, limit, tmp, result); - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR); - assert(base_offset % 8 == 0, "Base offset must be 8-byte aligned"); - - if (is_array_equ) { - // return true if the same array - cmp(ary1, ary2); - brx(Assembler::equal, true, Assembler::pn, Ldone); - delayed()->mov(1, result); // equal - - br_null(ary1, true, Assembler::pn, Ldone); - delayed()->clr(result); // not equal - - br_null(ary2, true, Assembler::pn, Ldone); - delayed()->clr(result); // not equal - - // load the lengths of arrays - ld(Address(ary1, length_offset), limit); - ld(Address(ary2, length_offset), tmp); - - // return false if the two arrays are not equal length - cmp(limit, tmp); - br(Assembler::notEqual, true, Assembler::pn, Ldone); - delayed()->clr(result); // not equal - } - - cmp_zero_and_br(Assembler::zero, limit, Ldone, true, Assembler::pn); - delayed()->mov(1, result); // zero-length arrays are equal - - if (is_array_equ) { - // load array addresses - add(ary1, base_offset, ary1); - add(ary2, base_offset, ary2); - // set byte count - if (!is_byte) { - sll(limit, exact_log2(sizeof(jchar)), limit); - } - } else { - // We have no guarantee that on 64 bit the higher half of limit is 0 - signx(limit); - } - -#ifdef ASSERT - // Sanity check for doubleword (8-byte) alignment of ary1 and ary2. - // Guaranteed on 64-bit systems (see arrayOopDesc::header_size_in_bytes()). - Label Laligned; - or3(ary1, ary2, tmp); - andcc(tmp, 7, tmp); - br_null_short(tmp, Assembler::pn, Laligned); - STOP("First array element is not 8-byte aligned."); - should_not_reach_here(); - bind(Laligned); -#endif - - // Shift ary1 and ary2 to the end of the arrays, negate limit - add(ary1, limit, ary1); - add(ary2, limit, ary2); - neg(limit, limit); - - // MAIN LOOP - // Load and compare array elements of size 'byte_width' until the elements are not - // equal or we reached the end of the arrays. If the size of the arrays is not a - // multiple of 'byte_width', we simply read over the end of the array, bail out and - // compare the remaining bytes below by skipping the garbage bytes. - ldx(ary1, limit, result); - bind(Lloop); - ldx(ary2, limit, tmp); - inccc(limit, 8); - // Bail out if we reached the end (but still do the comparison) - br(Assembler::positive, false, Assembler::pn, Lremaining); - delayed()->cmp(result, tmp); - // Check equality of elements - brx(Assembler::equal, false, Assembler::pt, target(Lloop)); - delayed()->ldx(ary1, limit, result); - - ba(Ldone); - delayed()->clr(result); // not equal - - // TAIL COMPARISON - // We got here because we reached the end of the arrays. 'limit' is the number of - // garbage bytes we may have compared by reading over the end of the arrays. Shift - // out the garbage and compare the remaining elements. - bind(Lremaining); - // Optimistic shortcut: elements potentially including garbage are equal - brx(Assembler::equal, true, Assembler::pt, target(Ldone)); - delayed()->mov(1, result); // equal - // Shift 'limit' bytes to the right and compare - sll(limit, 3, limit); // bytes to bits - srlx(result, limit, result); - srlx(tmp, limit, tmp); - cmp(result, tmp); - clr(result); - movcc(Assembler::equal, false, xcc, 1, result); - - bind(Ldone); -} - -void C2_MacroAssembler::has_negatives(Register inp, Register size, Register result, Register t2, Register t3, Register t4, Register t5) { - - // test for negative bytes in input string of a given size - // result 1 if found, 0 otherwise. - - Label Lcore, Ltail, Lreturn, Lcore_rpt; - - assert_different_registers(inp, size, t2, t3, t4, t5, result); - - Register i = result; // result used as integer index i until very end - Register lmask = t2; // t2 is aliased to lmask - - // INITIALIZATION - // =========================================================== - // initialize highbits mask -> lmask = 0x8080808080808080 (8B/64b) - // compute unaligned offset -> i - // compute core end index -> t5 - Assembler::sethi(0x80808000, t2); //! sethi macro fails to emit optimal - add(t2, 0x80, t2); - sllx(t2, 32, t3); - or3(t3, t2, lmask); // 0x8080808080808080 -> lmask - sra(size,0,size); - andcc(inp, 0x7, i); // unaligned offset -> i - br(Assembler::zero, true, Assembler::pn, Lcore); // starts 8B aligned? - delayed()->add(size, -8, t5); // (annuled) core end index -> t5 - - // =========================================================== - - // UNALIGNED HEAD - // =========================================================== - // * unaligned head handling: grab aligned 8B containing unaligned inp(ut) - // * obliterate (ignore) bytes outside string by shifting off reg ends - // * compare with bitmask, short circuit return true if one or more high - // bits set. - cmp(size, 0); - br(Assembler::zero, true, Assembler::pn, Lreturn); // short-circuit? - delayed()->mov(0,result); // annuled so i not clobbered for following - neg(i, t4); - add(i, size, t5); - ldx(inp, t4, t3); // raw aligned 8B containing unaligned head -> t3 - mov(8, t4); - sub(t4, t5, t4); - sra(t4, 31, t5); - andn(t4, t5, t5); - add(i, t5, t4); - sll(t5, 3, t5); - sll(t4, 3, t4); // # bits to shift right, left -> t5,t4 - srlx(t3, t5, t3); - sllx(t3, t4, t3); // bytes outside string in 8B header obliterated -> t3 - andcc(lmask, t3, G0); - brx(Assembler::notZero, true, Assembler::pn, Lreturn); // short circuit? - delayed()->mov(1,result); // annuled so i not clobbered for following - add(size, -8, t5); // core end index -> t5 - mov(8, t4); - sub(t4, i, i); // # bytes examined in unalgn head (<8) -> i - // =========================================================== - - // ALIGNED CORE - // =========================================================== - // * iterate index i over aligned 8B sections of core, comparing with - // bitmask, short circuit return true if one or more high bits set - // t5 contains core end index/loop limit which is the index - // of the MSB of last (unaligned) 8B fully contained in the string. - // inp contains address of first byte in string/array - // lmask contains 8B high bit mask for comparison - // i contains next index to be processed (adr. inp+i is on 8B boundary) - bind(Lcore); - cmp_and_br_short(i, t5, Assembler::greater, Assembler::pn, Ltail); - bind(Lcore_rpt); - ldx(inp, i, t3); - andcc(t3, lmask, G0); - brx(Assembler::notZero, true, Assembler::pn, Lreturn); - delayed()->mov(1, result); // annuled so i not clobbered for following - add(i, 8, i); - cmp_and_br_short(i, t5, Assembler::lessEqual, Assembler::pn, Lcore_rpt); - // =========================================================== - - // ALIGNED TAIL (<8B) - // =========================================================== - // handle aligned tail of 7B or less as complete 8B, obliterating end of - // string bytes by shifting them off end, compare what's left with bitmask - // inp contains address of first byte in string/array - // lmask contains 8B high bit mask for comparison - // i contains next index to be processed (adr. inp+i is on 8B boundary) - bind(Ltail); - subcc(size, i, t4); // # of remaining bytes in string -> t4 - // return 0 if no more remaining bytes - br(Assembler::lessEqual, true, Assembler::pn, Lreturn); - delayed()->mov(0, result); // annuled so i not clobbered for following - ldx(inp, i, t3); // load final 8B (aligned) containing tail -> t3 - mov(8, t5); - sub(t5, t4, t4); - mov(0, result); // ** i clobbered at this point - sll(t4, 3, t4); // bits beyond end of string -> t4 - srlx(t3, t4, t3); // bytes beyond end now obliterated -> t3 - andcc(lmask, t3, G0); - movcc(Assembler::notZero, false, xcc, 1, result); - bind(Lreturn); -} - diff --git a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c2_MacroAssembler_sparc.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2020, 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. - * - */ - -#ifndef CPU_SPARC_C2_MACROASSEMBLER_SPARC_HPP -#define CPU_SPARC_C2_MACROASSEMBLER_SPARC_HPP - -// C2_MacroAssembler contains high-level macros for C2 - - public: - // Compress char[] to byte[] by compressing 16 bytes at once. Return 0 on failure. - void string_compress_16(Register src, Register dst, Register cnt, Register result, - Register tmp1, Register tmp2, Register tmp3, Register tmp4, - FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, Label& Ldone); - - // Compress char[] to byte[]. Return 0 on failure. - void string_compress(Register src, Register dst, Register cnt, Register tmp, Register result, Label& Ldone); - - // Inflate byte[] to char[] by inflating 16 bytes at once. - void string_inflate_16(Register src, Register dst, Register cnt, Register tmp, - FloatRegister ftmp1, FloatRegister ftmp2, FloatRegister ftmp3, FloatRegister ftmp4, Label& Ldone); - - // Inflate byte[] to char[]. - void string_inflate(Register src, Register dst, Register cnt, Register tmp, Label& Ldone); - - void string_compare(Register str1, Register str2, - Register cnt1, Register cnt2, - Register tmp1, Register tmp2, - Register result, int ae); - - void array_equals(bool is_array_equ, Register ary1, Register ary2, - Register limit, Register tmp, Register result, bool is_byte); - // test for negative bytes in input string of a given size, result 0 if none - void has_negatives(Register inp, Register size, Register result, - Register t2, Register t3, Register t4, - Register t5); - -#endif // CPU_SPARC_C2_MACROASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c2_globals_sparc.hpp b/src/hotspot/cpu/sparc/c2_globals_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c2_globals_sparc.hpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef CPU_SPARC_C2_GLOBALS_SPARC_HPP -#define CPU_SPARC_C2_GLOBALS_SPARC_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, 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); -define_pd_global(bool, ProfileInterpreter, true); -define_pd_global(bool, TieredCompilation, trueInTiered); -define_pd_global(intx, CompileThreshold, 10000); - -define_pd_global(intx, OnStackReplacePercentage, 140); -define_pd_global(intx, ConditionalMoveLimit, 4); -define_pd_global(intx, FLOATPRESSURE, 52); // C2 on V9 gets to use all the float/double registers -define_pd_global(intx, FreqInlineSize, 175); -define_pd_global(intx, INTPRESSURE, 48); // large register set -define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment -define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); -define_pd_global(intx, RegisterCostAreaRatio, 12000); -define_pd_global(bool, UseTLAB, true); -define_pd_global(bool, ResizeTLAB, true); -define_pd_global(intx, LoopUnrollLimit, 60); // Design center runs on 1.3.1 -define_pd_global(intx, LoopPercentProfileLimit, 10); -define_pd_global(intx, MinJumpTableSize, 5); - -// Peephole and CISC spilling both break the graph, and so makes the -// scheduler sick. -define_pd_global(bool, OptoPeephole, false); -define_pd_global(bool, UseCISCSpill, false); -define_pd_global(bool, OptoBundling, false); -define_pd_global(bool, OptoScheduling, true); -define_pd_global(bool, OptoRegScheduling, false); -define_pd_global(bool, SuperWordLoopUnrollAnalysis, false); -define_pd_global(bool, IdealizeClearArrayNode, true); - -// We need to make sure that all generated code is within -// 2 gigs of the libjvm.so runtime routines so we can use -// the faster "call" instruction rather than the expensive -// sequence of instructions to load a 64 bit pointer. -// -// InitialCodeCacheSize derived from specjbb2000 run. -define_pd_global(uintx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize -define_pd_global(uintx, ReservedCodeCacheSize, 48*M); -define_pd_global(uintx, NonProfiledCodeHeapSize, 21*M); -define_pd_global(uintx, ProfiledCodeHeapSize, 22*M); -define_pd_global(uintx, NonNMethodCodeHeapSize, 5*M ); -define_pd_global(uintx, CodeCacheExpansionSize, 64*K); - -// Ergonomics related flags -define_pd_global(uint64_t,MaxRAM, 128ULL*G); -define_pd_global(uintx, CodeCacheMinBlockLength, 6); -define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); - -define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed on sparc. - -// Heap related flags -define_pd_global(size_t, MetaspaceSize, ScaleForWordSize(16*M)); - -// Ergonomics related flags -define_pd_global(bool, NeverActAsServerClassMachine, false); - -#endif // CPU_SPARC_C2_GLOBALS_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/c2_init_sparc.cpp b/src/hotspot/cpu/sparc/c2_init_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/c2_init_sparc.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2000, 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. - * - */ - -#include "precompiled.hpp" -#include "opto/compile.hpp" -#include "opto/node.hpp" - -// processor dependent initialization for sparc - -void Compile::pd_compiler2_init() { - guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" ); -} diff --git a/src/hotspot/cpu/sparc/codeBuffer_sparc.hpp b/src/hotspot/cpu/sparc/codeBuffer_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/codeBuffer_sparc.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2002, 2019, 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. - * - */ - -#ifndef CPU_SPARC_CODEBUFFER_SPARC_HPP -#define CPU_SPARC_CODEBUFFER_SPARC_HPP - -private: - void pd_initialize() {} - -public: - void flush_bundle(bool start_new_bundle) {} - -#endif // CPU_SPARC_CODEBUFFER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/compiledIC_sparc.cpp b/src/hotspot/cpu/sparc/compiledIC_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/compiledIC_sparc.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#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" -#ifdef COMPILER2 -#include "opto/matcher.hpp" -#endif - -// ---------------------------------------------------------------------------- - -#define __ _masm. -address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { - // Stub is fixed up when the corresponding call is converted from calling - // compiled code to calling interpreted code. - // set (empty), G5 - // jmp -1 - - if (mark == NULL) { - mark = cbuf.insts_mark(); // Get mark within main instrs section. - } - - MacroAssembler _masm(&cbuf); - - address base = __ start_a_stub(to_interp_stub_size()); - if (base == NULL) { - return NULL; // CodeBuffer::expand failed. - } - - // Static stub relocation stores the instruction address of the call. - __ relocate(static_stub_Relocation::spec(mark)); - - __ set_metadata(NULL, as_Register(Matcher::inline_cache_reg_encode())); - - __ set_inst_mark(); - AddressLiteral addrlit(-1); - __ JUMP(addrlit, G3, 0); - - __ delayed()->nop(); - - assert(__ pc() - base <= to_interp_stub_size(), "wrong stub size"); - - // Update current stubs pointer and restore code_end. - __ end_a_stub(); - return base; -} -#undef __ - -int CompiledStaticCall::to_trampoline_stub_size() { - // SPARC doesn't use trampolines. - return 0; -} - -int CompiledStaticCall::to_interp_stub_size() { - // This doesn't need to be accurate but it must be larger or equal to - // the real size of the stub. - return (NativeMovConstReg::instruction_size + // sethi/setlo; - NativeJump::instruction_size); // sethi; jmp; nop -} - -// Relocation entries for call stub, compiled java to interpreter. -int CompiledStaticCall::reloc_to_interp_stub() { - return 10; // 4 in emit_java_to_interp + 1 in Java_Static_Call -} - -void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { - address stub = find_stub(/*is_aot*/ false); - guarantee(stub != NULL, "stub not found"); - - if (TraceICs) { - ResourceMark rm; - tty->print_cr("CompiledDirectStaticCall@" 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); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - verify_mt_safe(callee, entry, method_holder, jump); - - // Update stub. - method_holder->set_data((intptr_t)callee()); - jump->set_jump_destination(entry); - - // Update jump to call. - set_destination_mt_safe(stub); -} - -void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { - // Reset stub. - address stub = static_stub->addr(); - assert(stub != NULL, "stub not found"); - assert(CompiledICLocker::is_safe(stub), "mt unsafe call"); - // Creation also verifies the object. - NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); - method_holder->set_data(0); - jump->set_jump_destination((address)-1); -} - -//----------------------------------------------------------------------------- -// Non-product mode code -#ifndef PRODUCT - -void CompiledDirectStaticCall::verify() { - // Verify call. - _call->verify(); - _call->verify_alignment(); - - // Verify stub. - address stub = find_stub(/*is_aot*/ false); - 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 diff --git a/src/hotspot/cpu/sparc/copy_sparc.hpp b/src/hotspot/cpu/sparc/copy_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/copy_sparc.hpp +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef CPU_SPARC_COPY_SPARC_HPP -#define CPU_SPARC_COPY_SPARC_HPP - -// Inline functions for memory copy and fill. - -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - (void)memmove(to, from, count * HeapWordSize); -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: (void)memcpy(to, from, count * HeapWordSize); - break; - } -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: while (count-- > 0) { - *to++ = *from++; - } - break; - } -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - (void)memmove(to, from, count * HeapWordSize); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { - (void)memmove(to, from, count); -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - (void)memmove(to, from, count); -} - -static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } -} - -static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } -} - -static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); -} - -static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { - // Do better than this: inline memmove body NEEDS CLEANUP - if (from > to) { - while (count-- > 0) { - // Copy forwards - *to++ = *from++; - } - } else { - from += count - 1; - to += count - 1; - while (count-- > 0) { - // Copy backwards - *to-- = *from--; - } - } -} - -static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_bytes_atomic(from, to, count); -} - -static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_jshorts_atomic((const jshort*)from, (jshort*)to, count); -} - -static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_jints_atomic((const jint*)from, (jint*)to, count); -} - -static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -} - -static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { - pd_conjoint_oops_atomic((const oop*)from, (oop*)to, count); -} - -static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) { - guarantee(mask_bits((uintptr_t)tohw, right_n_bits(LogBytesPerLong)) == 0, - "unaligned fill words"); - julong* to = (julong*)tohw; - julong v = ((julong)value << 32) | value; - while (count-- > 0) { - *to++ = v; - } -} - -typedef void (*_zero_Fn)(HeapWord* to, size_t count); - -// Only used for heap objects, so align_object_offset. -// All other platforms pd_fill_to_aligned_words simply calls pd_fill_to_words, don't -// know why this one is different. -static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) { - assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation"); - - if (value == 0 && UseBlockZeroing && - (count > (size_t)(BlockZeroingLowLimit >> LogHeapWordSize))) { - // Call it only when block zeroing is used - ((_zero_Fn)StubRoutines::zero_aligned_words())(tohw, count); - } else { - julong* to = (julong*)tohw; - julong v = ((julong)value << 32) | value; - // If count is odd, odd will be equal to 1 on 32-bit platform - // and be equal to 0 on 64-bit platform. - size_t odd = count % (BytesPerLong / HeapWordSize) ; - - size_t aligned_count = align_object_offset(count - odd) / HeapWordsPerLong; - julong* end = ((julong*)tohw) + aligned_count - 1; - while (to <= end) { - DEBUG_ONLY(count -= BytesPerLong / HeapWordSize ;) - *to++ = v; - } - assert(count == odd, "bad bounds on loop filling to aligned words"); - if (odd) { - *((juint*)to) = 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_SPARC_COPY_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/depChecker_sparc.cpp b/src/hotspot/cpu/sparc/depChecker_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/depChecker_sparc.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2002, 2010, 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. - * - */ - -#include "precompiled.hpp" -#include "compiler/disassembler.hpp" -#include "depChecker_sparc.hpp" - -// Nothing to do on Sparc diff --git a/src/hotspot/cpu/sparc/depChecker_sparc.hpp b/src/hotspot/cpu/sparc/depChecker_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/depChecker_sparc.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2002, 2019, 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. - * - */ - -#ifndef CPU_SPARC_DEPCHECKER_SPARC_HPP -#define CPU_SPARC_DEPCHECKER_SPARC_HPP - -// Nothing to do on Sparc - -#endif // CPU_SPARC_DEPCHECKER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/disassembler_sparc.hpp b/src/hotspot/cpu/sparc/disassembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/disassembler_sparc.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_DISASSEMBLER_SPARC_HPP -#define CPU_SPARC_DISASSEMBLER_SPARC_HPP - - static int pd_instruction_alignment() { - return sizeof(int); - } - - static const char* pd_cpu_opts() { - return "v9only"; - } - - // Returns address of n-th instruction preceding addr, - // NULL if no preceding instruction can be found. - // With SPARC being a RISC architecture, this always is BytesPerInstWord - // It might be beneficial to check "is_readable" as we do on ppc and s390. - static address find_prev_instr(address addr, int n_instr) { - return addr - BytesPerInstWord*n_instr; - } - - // special-case instruction decoding. - // There may be cases where the binutils disassembler doesn't do - // the perfect job. In those cases, decode_instruction0 may kick in - // and do it right. - // If nothing had to be done, just return "here", otherwise return "here + instr_len(here)" - static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) { - return here; - } - - // platform-specific instruction annotations (like value of loaded constants) - static void annotate(address pc, outputStream* st) { }; - -#endif // CPU_SPARC_DISASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/frame_sparc.cpp b/src/hotspot/cpu/sparc/frame_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/frame_sparc.cpp +++ /dev/null @@ -1,822 +0,0 @@ -/* - * Copyright (c) 1997, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "code/codeCache.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "oops/markWord.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/signature.hpp" -#include "runtime/stubCodeGenerator.hpp" -#include "runtime/stubRoutines.hpp" -#include "vmreg_sparc.inline.hpp" -#ifdef COMPILER1 -#include "c1/c1_Runtime1.hpp" -#include "runtime/vframeArray.hpp" -#endif - -void RegisterMap::pd_clear() { - if (_thread->has_last_Java_frame()) { - frame fr = _thread->last_frame(); - _window = fr.sp(); - } else { - _window = NULL; - } - _younger_window = NULL; -} - - -// Unified register numbering scheme: each 32-bits counts as a register -// number, so all the V9 registers take 2 slots. -const static int R_L_nums[] = {0+040,2+040,4+040,6+040,8+040,10+040,12+040,14+040}; -const static int R_I_nums[] = {0+060,2+060,4+060,6+060,8+060,10+060,12+060,14+060}; -const static int R_O_nums[] = {0+020,2+020,4+020,6+020,8+020,10+020,12+020,14+020}; -const static int R_G_nums[] = {0+000,2+000,4+000,6+000,8+000,10+000,12+000,14+000}; -static RegisterMap::LocationValidType bad_mask = 0; -static RegisterMap::LocationValidType R_LIO_mask = 0; -static bool register_map_inited = false; - -static void register_map_init() { - if (!register_map_inited) { - register_map_inited = true; - int i; - for (i = 0; i < 8; i++) { - assert(R_L_nums[i] < RegisterMap::location_valid_type_size, "in first chunk"); - assert(R_I_nums[i] < RegisterMap::location_valid_type_size, "in first chunk"); - assert(R_O_nums[i] < RegisterMap::location_valid_type_size, "in first chunk"); - assert(R_G_nums[i] < RegisterMap::location_valid_type_size, "in first chunk"); - } - - bad_mask |= (1LL << R_O_nums[6]); // SP - bad_mask |= (1LL << R_O_nums[7]); // cPC - bad_mask |= (1LL << R_I_nums[6]); // FP - bad_mask |= (1LL << R_I_nums[7]); // rPC - bad_mask |= (1LL << R_G_nums[2]); // TLS - bad_mask |= (1LL << R_G_nums[7]); // reserved by libthread - - for (i = 0; i < 8; i++) { - R_LIO_mask |= (1LL << R_L_nums[i]); - R_LIO_mask |= (1LL << R_I_nums[i]); - R_LIO_mask |= (1LL << R_O_nums[i]); - } - } -} - - -address RegisterMap::pd_location(VMReg regname) const { - register_map_init(); - - assert(regname->is_reg(), "sanity check"); - // Only the GPRs get handled this way - if( !regname->is_Register()) - return NULL; - - // don't talk about bad registers - if ((bad_mask & ((LocationValidType)1 << regname->value())) != 0) { - return NULL; - } - - // Convert to a GPR - Register reg; - int second_word = 0; - // 32-bit registers for in, out and local - if (!regname->is_concrete()) { - // HMM ought to return NULL for any non-concrete (odd) vmreg - // this all tied up in the fact we put out double oopMaps for - // register locations. When that is fixed we'd will return NULL - // (or assert here). - reg = regname->prev()->as_Register(); - second_word = sizeof(jint); - } else { - reg = regname->as_Register(); - } - if (reg->is_out()) { - return _younger_window == NULL ? NULL : - second_word + (address)&_younger_window[reg->after_save()->sp_offset_in_saved_window()]; - } - if (reg->is_local() || reg->is_in()) { - assert(_window != NULL, "Window should be available"); - return second_word + (address)&_window[reg->sp_offset_in_saved_window()]; - } - // Only the window'd GPRs get handled this way; not the globals. - return NULL; -} - - -#ifdef ASSERT -void RegisterMap::check_location_valid() { - register_map_init(); - assert((_location_valid[0] & bad_mask) == 0, "cannot have special locations for SP,FP,TLS,etc."); -} -#endif - -// We are shifting windows. That means we are moving all %i to %o, -// getting rid of all current %l, and keeping all %g. This is only -// complicated if any of the location pointers for these are valid. -// The normal case is that everything is in its standard register window -// home, and _location_valid[0] is zero. In that case, this routine -// does exactly nothing. -void RegisterMap::shift_individual_registers() { - if (!update_map()) return; // this only applies to maps with locations - register_map_init(); - check_location_valid(); - - LocationValidType lv = _location_valid[0]; - LocationValidType lv0 = lv; - - lv &= ~R_LIO_mask; // clear %l, %o, %i regs - - // if we cleared some non-%g locations, we may have to do some shifting - if (lv != lv0) { - // copy %i0-%i5 to %o0-%o5, if they have special locations - // This can happen in within stubs which spill argument registers - // around a dynamic link operation, such as resolve_opt_virtual_call. - for (int i = 0; i < 8; i++) { - if (lv0 & (1LL << R_I_nums[i])) { - _location[R_O_nums[i]] = _location[R_I_nums[i]]; - lv |= (1LL << R_O_nums[i]); - } - } - } - - _location_valid[0] = lv; - check_location_valid(); -} - -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 - // sp must be within the usable part of the stack (not in guards) - if (!thread->is_in_usable_stack(_SP)) { - return false; - } - - // unextended sp must be within the stack and above or equal sp - if (!thread->is_in_stack_range_incl(_UNEXTENDED_SP, _SP)) { - return false; - } - - // an fp must be within the stack and above (but not equal) sp - bool fp_safe = thread->is_in_stack_range_excl(_FP, _SP); - - // 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_compiled() || _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. - return fp_safe && is_entry_frame_valid(thread); - } - - intptr_t* younger_sp = sp(); - intptr_t* _SENDER_SP = sender_sp(); // sender is actually just _FP - bool adjusted_stack = is_interpreted_frame(); - - address sender_pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset; - - - // 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; - } - - // It should be safe to construct the sender though it might not be valid - - frame sender(_SENDER_SP, younger_sp, adjusted_stack); - - // Do we have a valid fp? - address sender_fp = (address) sender.fp(); - - // an fp must be within the stack and above (but not equal) current frame's _FP - - if (!thread->is_in_stack_range_excl(sender_fp, _FP)) { - return false; - } - - - // If the potential sender is the interpreter then we can do some more checking - if (Interpreter::contains(sender_pc)) { - return sender.is_interpreted_frame_valid(thread); - } - - // Could just be some random pointer within the codeBlob - if (!sender.cb()->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; - } - - if (sender.is_entry_frame()) { - // Validate the JavaCallWrapper an entry frame must have - address jcw = (address)sender.entry_frame_call_wrapper(); - - return thread->is_in_stack_range_excl(jcw, sender_fp); - } - - // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size - // because you must allocate window space - - if (sender_blob->frame_size() <= 0) { - assert(!sender_blob->is_compiled(), "should count return address at least"); - return false; - } - - // The sender should positively be an nmethod or call_stub. On sparc we might in fact see something else. - // The cause of this is because at a save instruction the O7 we get is a leftover from an earlier - // window use. So if a runtime stub creates two frames (common in fastdebug/debug) then we see the - // stale pc. So if the sender blob is not something we'd expect we have little choice but to declare - // the stack unwalkable. pd_get_top_frame_for_signal_handler tries to recover from this by unwinding - // that initial frame and retrying. - - if (!sender_blob->is_compiled()) { - 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; - - // could try and do some more potential verification of native frame if we could think of some... - - return true; -} - -// constructors - -// Construct an unpatchable, deficient frame -void frame::init(intptr_t* sp, address pc, CodeBlob* cb) { - assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp"); - _sp = sp; - _younger_sp = NULL; - _pc = pc; - _cb = cb; - _sp_adjustment_by_callee = 0; - assert(pc == NULL && cb == NULL || pc != NULL, "can't have a cb and no pc!"); - if (_cb == NULL && _pc != NULL ) { - _cb = CodeCache::find_blob(_pc); - } - _deopt_state = unknown; -} - -frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) { - init(sp, pc, cb); -} - -frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) : - _sp(sp), - _younger_sp(younger_sp), - _deopt_state(unknown), - _sp_adjustment_by_callee(0) { - if (younger_sp == NULL) { - // make a deficient frame which doesn't know where its PC is - _pc = NULL; - _cb = NULL; - } else { - _pc = (address)younger_sp[I7->sp_offset_in_saved_window()] + pc_return_offset; - assert( (intptr_t*)younger_sp[FP->sp_offset_in_saved_window()] == (intptr_t*)((intptr_t)sp - STACK_BIAS), "younger_sp must be valid"); - // Any frame we ever build should always "safe" therefore we should not have to call - // find_blob_unsafe - // In case of native stubs, the pc retrieved here might be - // wrong. (the _last_native_pc will have the right value) - // So do not put add any asserts on the _pc here. - } - - if (_pc != NULL) - _cb = CodeCache::find_blob(_pc); - - // Check for MethodHandle call sites. - if (_cb != NULL) { - CompiledMethod* nm = _cb->as_compiled_method_or_null(); - if (nm != NULL) { - if (nm->is_deopt_mh_entry(_pc) || nm->is_method_handle_return(_pc)) { - _sp_adjustment_by_callee = (intptr_t*) ((intptr_t) sp[L7_mh_SP_save->sp_offset_in_saved_window()] + STACK_BIAS) - sp; - // The SP is already adjusted by this MH call site, don't - // overwrite this value with the wrong interpreter value. - younger_frame_is_interpreted = false; - } - } - } - - if (younger_frame_is_interpreted) { - // compute adjustment to this frame's SP made by its interpreted callee - _sp_adjustment_by_callee = (intptr_t*) ((intptr_t) younger_sp[I5_savedSP->sp_offset_in_saved_window()] + STACK_BIAS) - sp; - } - - // It is important that the frame is fully constructed when we do - // this lookup as get_deopt_original_pc() needs a correct value for - // unextended_sp() which uses _sp_adjustment_by_callee. - if (_pc != NULL) { - address original_pc = CompiledMethod::get_deopt_original_pc(this); - if (original_pc != NULL) { - _pc = original_pc; - _deopt_state = is_deoptimized; - } else { - _deopt_state = not_deoptimized; - } - } -} - -#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, (address)pc, NULL); -} - -extern "C" void findpc(intptr_t x); - -void frame::pd_ps() { - intptr_t* curr_sp = sp(); - intptr_t* prev_sp = curr_sp - 1; - intptr_t *pc = NULL; - intptr_t *next_pc = NULL; - int count = 0; - tty->print_cr("register window backtrace from " INTPTR_FORMAT ":", p2i(curr_sp)); - while (curr_sp != NULL && ((intptr_t)curr_sp & 7) == 0 && curr_sp > prev_sp && curr_sp < prev_sp+1000) { - pc = next_pc; - next_pc = (intptr_t*) curr_sp[I7->sp_offset_in_saved_window()]; - tty->print("[%d] curr_sp=" INTPTR_FORMAT " pc=", count, p2i(curr_sp)); - findpc((intptr_t)pc); - if (WizardMode && Verbose) { - // print register window contents also - tty->print_cr(" L0..L7: {" - INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " - INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " ", - curr_sp[0+0], curr_sp[0+1], curr_sp[0+2], curr_sp[0+3], - curr_sp[0+4], curr_sp[0+5], curr_sp[0+6], curr_sp[0+7]); - tty->print_cr(" I0..I7: {" - INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " - INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " " INTPTR_FORMAT " ", - curr_sp[8+0], curr_sp[8+1], curr_sp[8+2], curr_sp[8+3], - curr_sp[8+4], curr_sp[8+5], curr_sp[8+6], curr_sp[8+7]); - // (and print stack frame contents too??) - - CodeBlob *b = CodeCache::find_blob((address) pc); - if (b != NULL) { - if (b->is_nmethod()) { - Method* m = ((nmethod*)b)->method(); - int nlocals = m->max_locals(); - int nparams = m->size_of_parameters(); - tty->print_cr("compiled java method (locals = %d, params = %d)", nlocals, nparams); - } - } - } - prev_sp = curr_sp; - curr_sp = (intptr_t *)curr_sp[FP->sp_offset_in_saved_window()]; - curr_sp = (intptr_t *)((intptr_t)curr_sp + STACK_BIAS); - count += 1; - } - if (curr_sp != NULL) - tty->print("[%d] curr_sp=" INTPTR_FORMAT " [bogus sp!]", count, p2i(curr_sp)); -} - -#endif // PRODUCT - -bool frame::is_interpreted_frame() const { - return Interpreter::contains(pc()); -} - -// sender_sp - -intptr_t* frame::interpreter_frame_sender_sp() const { - assert(is_interpreted_frame(), "interpreted frame expected"); - return fp(); -} - -void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) { - assert(is_interpreted_frame(), "interpreted frame expected"); - Unimplemented(); -} - -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"); - intptr_t* last_Java_sp = jfa->last_Java_sp(); - // Since we are walking the stack now this nested anchor is obviously walkable - // even if it wasn't when it was stacked. - if (!jfa->walkable()) { - // Capture _last_Java_pc (if needed) and mark anchor walkable. - jfa->capture_last_Java_pc(_sp); - } - assert(jfa->last_Java_pc() != NULL, "No captured pc!"); - map->clear(); - map->make_integer_regs_unsaved(); - map->shift_window(last_Java_sp, NULL); - assert(map->include_argument_oops(), "should be set by clear"); - return frame(last_Java_sp, frame::unpatchable, jfa->last_Java_pc()); -} - -frame frame::sender_for_interpreter_frame(RegisterMap *map) const { - ShouldNotCallThis(); - return sender(map); -} - -frame frame::sender_for_compiled_frame(RegisterMap *map) const { - ShouldNotCallThis(); - return sender(map); -} - -frame frame::sender(RegisterMap* map) const { - assert(map != NULL, "map must be set"); - - assert(CodeCache::find_blob_unsafe(_pc) == _cb, "inconsistent"); - - // Default is not to follow arguments; update it accordingly below - map->set_include_argument_oops(false); - - if (is_entry_frame()) return sender_for_entry_frame(map); - - intptr_t* younger_sp = sp(); - intptr_t* sp = sender_sp(); - - // Note: The version of this operation on any platform with callee-save - // registers must update the register map (if not null). - // In order to do this correctly, the various subtypes of - // of frame (interpreted, compiled, glue, native), - // must be distinguished. There is no need on SPARC for - // such distinctions, because all callee-save registers are - // preserved for all frames via SPARC-specific mechanisms. - // - // *** HOWEVER, *** if and when we make any floating-point - // registers callee-saved, then we will have to copy over - // the RegisterMap update logic from the Intel code. - - // The constructor of the sender must know whether this frame is interpreted so it can set the - // sender's _sp_adjustment_by_callee field. An osr adapter frame was originally - // interpreted but its pc is in the code cache (for c1 -> osr_frame_return_id stub), so it must be - // explicitly recognized. - - - bool frame_is_interpreted = is_interpreted_frame(); - if (frame_is_interpreted) { - map->make_integer_regs_unsaved(); - map->shift_window(sp, younger_sp); - } else if (_cb != NULL) { - // Update the locations of implicitly saved registers to be their - // addresses in the register save area. - // For %o registers, the addresses of %i registers in the next younger - // frame are used. - map->shift_window(sp, younger_sp); - 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); - } - } - } - return frame(sp, younger_sp, frame_is_interpreted); -} - - -void frame::patch_pc(Thread* thread, address pc) { - assert(_cb == CodeCache::find_blob(pc), "unexpected pc"); - vmassert(_deopt_state != unknown, "frame is unpatchable"); - if (thread == Thread::current()) { - StubRoutines::Sparc::flush_callers_register_windows_func()(); - } - if (TracePcPatching) { - // QQQ this assert is invalid (or too strong anyway) sice _pc could - // be original pc and frame could have the deopt pc. - // assert(_pc == *O7_addr() + pc_return_offset, "frame has wrong pc"); - tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", - p2i(O7_addr()), p2i(_pc), p2i(pc)); - } - *O7_addr() = pc - pc_return_offset; - address original_pc = CompiledMethod::get_deopt_original_pc(this); - if (original_pc != NULL) { - assert(original_pc == _pc, "expected original to be stored before patching"); - _deopt_state = is_deoptimized; - } else { - _deopt_state = not_deoptimized; - } -} - - -static bool sp_is_valid(intptr_t* old_sp, intptr_t* young_sp, intptr_t* sp) { - return (((intptr_t)sp & (2*wordSize-1)) == 0 && - sp <= old_sp && - sp >= young_sp); -} - - -/* - Find the (biased) sp that is just younger than old_sp starting at sp. - If not found return NULL. Register windows are assumed to be flushed. -*/ -intptr_t* frame::next_younger_sp_or_null(intptr_t* old_sp, intptr_t* sp) { - - intptr_t* previous_sp = NULL; - intptr_t* orig_sp = sp; - - int max_frames = (old_sp - sp) / 16; // Minimum frame size is 16 - int max_frame2 = max_frames; - while(sp != old_sp && sp_is_valid(old_sp, orig_sp, sp)) { - if (max_frames-- <= 0) - // too many frames have gone by; invalid parameters given to this function - break; - previous_sp = sp; - sp = (intptr_t*)sp[FP->sp_offset_in_saved_window()]; - sp = (intptr_t*)((intptr_t)sp + STACK_BIAS); - } - - return (sp == old_sp ? previous_sp : NULL); -} - -/* - Determine if "sp" is a valid stack pointer. "sp" is assumed to be younger than - "valid_sp". So if "sp" is valid itself then it should be possible to walk frames - from "sp" to "valid_sp". The assumption is that the registers windows for the - thread stack in question are flushed. -*/ -bool frame::is_valid_stack_pointer(intptr_t* valid_sp, intptr_t* sp) { - return next_younger_sp_or_null(valid_sp, sp) != NULL; -} - -bool frame::is_interpreted_frame_valid(JavaThread* thread) const { - assert(is_interpreted_frame(), "Not an interpreted frame"); - // These are reasonable sanity checks - if (fp() == 0 || (intptr_t(fp()) & (2*wordSize-1)) != 0) { - return false; - } - if (sp() == 0 || (intptr_t(sp()) & (2*wordSize-1)) != 0) { - return false; - } - - const intptr_t interpreter_frame_initial_sp_offset = interpreter_frame_vm_local_words; - 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 (!Method::is_valid_method(m)) return false; - - // stack frames shouldn't be much larger than max_stack elements - - if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) { - return false; - } - - // validate bci/bcp - - address bcp = interpreter_frame_bcp(); - if (m->validate_bci_from_bcp(bcp) < 0) { - return false; - } - - // validate ConstantPoolCache* - ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (MetaspaceObj::is_valid(cp) == false) return false; - - // validate locals - - address locals = (address) *interpreter_frame_locals_addr(); - return thread->is_in_stack_range_incl(locals, (address)fp()); -} - - -// Windows have been flushed on entry (but not marked). Capture the pc that -// is the return address to the frame that contains "sp" as its stack pointer. -// This pc resides in the called of the frame corresponding to "sp". -// As a side effect we mark this JavaFrameAnchor as having flushed the windows. -// This side effect lets us mark stacked JavaFrameAnchors (stacked in the -// call_helper) as flushed when we have flushed the windows for the most -// recent (i.e. current) JavaFrameAnchor. This saves useless flushing calls -// and lets us find the pc just once rather than multiple times as it did -// in the bad old _post_Java_state days. -// -void JavaFrameAnchor::capture_last_Java_pc(intptr_t* sp) { - if (last_Java_sp() != NULL && last_Java_pc() == NULL) { - // try and find the sp just younger than _last_Java_sp - intptr_t* _post_Java_sp = frame::next_younger_sp_or_null(last_Java_sp(), sp); - // Really this should never fail otherwise VM call must have non-standard - // frame linkage (bad) or stack is not properly flushed (worse). - guarantee(_post_Java_sp != NULL, "bad stack!"); - _last_Java_pc = (address) _post_Java_sp[ I7->sp_offset_in_saved_window()] + frame::pc_return_offset; - - } - set_window_flushed(); -} - -void JavaFrameAnchor::make_walkable(JavaThread* thread) { - if (walkable()) return; - // Eventually make an assert - guarantee(Thread::current() == (Thread*)thread, "only current thread can flush its registers"); - // We always flush in case the profiler wants it but we won't mark - // the windows as flushed unless we have a last_Java_frame - intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()(); - if (last_Java_sp() != NULL ) { - capture_last_Java_pc(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); - - intptr_t* LSP = (intptr_t*) sp()[Lentry_args->sp_offset_in_saved_window()]; - return &LSP[index+1]; -} - - -BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { - assert(is_interpreted_frame(), "interpreted frame expected"); - Method* method = interpreter_frame_method(); - BasicType type = method->result_type(); - - if (method->is_native()) { - // Prior to notifying the runtime of the method_exit the possible result - // value is saved to l_scratch and d_scratch. - - intptr_t* l_scratch = fp() + interpreter_frame_l_scratch_fp_offset; - intptr_t* d_scratch = fp() + interpreter_frame_d_scratch_fp_offset; - - address l_addr = (address)l_scratch; - // On 64-bit the result for 1/8/16/32-bit result types is in the other - // word half - l_addr += wordSize/2; - - switch (type) { - case T_OBJECT: - case T_ARRAY: { - oop obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); - assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); - *oop_result = obj; - break; - } - - case T_BOOLEAN : { jint* p = (jint*)l_addr; value_result->z = (jboolean)((*p) & 0x1); break; } - case T_BYTE : { jint* p = (jint*)l_addr; value_result->b = (jbyte)((*p) & 0xff); break; } - case T_CHAR : { jint* p = (jint*)l_addr; value_result->c = (jchar)((*p) & 0xffff); break; } - case T_SHORT : { jint* p = (jint*)l_addr; value_result->s = (jshort)((*p) & 0xffff); break; } - case T_INT : value_result->i = *(jint*)l_addr; break; - case T_LONG : value_result->j = *(jlong*)l_scratch; break; - case T_FLOAT : value_result->f = *(jfloat*)d_scratch; break; - case T_DOUBLE : value_result->d = *(jdouble*)d_scratch; break; - case T_VOID : /* Nothing to do */ break; - default : ShouldNotReachHere(); - } - } else { - intptr_t* tos_addr = interpreter_frame_tos_address(); - - switch(type) { - case T_OBJECT: - case T_ARRAY: { - oop obj = cast_to_oop(*tos_addr); - assert(obj == NULL || Universe::heap()->is_in(obj), "sanity check"); - *oop_result = obj; - break; - } - case T_BOOLEAN : { jint* p = (jint*)tos_addr; value_result->z = (jboolean)((*p) & 0x1); break; } - case T_BYTE : { jint* p = (jint*)tos_addr; value_result->b = (jbyte)((*p) & 0xff); break; } - case T_CHAR : { jint* p = (jint*)tos_addr; value_result->c = (jchar)((*p) & 0xffff); break; } - case T_SHORT : { jint* p = (jint*)tos_addr; value_result->s = (jshort)((*p) & 0xffff); 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; -} - -// Lesp pointer is one word lower than the top item on the stack. -intptr_t* frame::interpreter_frame_tos_at(jint offset) const { - int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize) - 1; - 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) { - for (int w = 0; w < frame::register_save_words; w++) { - values.describe(frame_no, sp() + w, err_msg("register save area word %d", w), 1); - } - - if (is_interpreted_frame()) { - DESCRIBE_FP_OFFSET(interpreter_frame_d_scratch_fp); - DESCRIBE_FP_OFFSET(interpreter_frame_l_scratch_fp); - DESCRIBE_FP_OFFSET(interpreter_frame_mirror); - DESCRIBE_FP_OFFSET(interpreter_frame_oop_temp); - - // esp, according to Lesp (e.g. not depending on bci), if seems valid - intptr_t* esp = *interpreter_frame_esp_addr(); - if ((esp >= sp()) && (esp < fp())) { - values.describe(-1, esp, "*Lesp"); - } - } - - if (!is_compiled_frame()) { - if (frame::callee_aggregate_return_pointer_words != 0) { - values.describe(frame_no, sp() + frame::callee_aggregate_return_pointer_sp_offset, "callee_aggregate_return_pointer_word"); - } - for (int w = 0; w < frame::callee_register_argument_save_area_words; w++) { - values.describe(frame_no, sp() + frame::callee_register_argument_save_area_sp_offset + w, - err_msg("callee_register_argument_save_area_words %d", w)); - } - } -} - -#endif - -intptr_t *frame::initial_deoptimization_info() { - // unused... but returns fp() to minimize changes introduced by 7087445 - return fp(); -} diff --git a/src/hotspot/cpu/sparc/frame_sparc.hpp b/src/hotspot/cpu/sparc/frame_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/frame_sparc.hpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_FRAME_SPARC_HPP -#define CPU_SPARC_FRAME_SPARC_HPP - -#include "runtime/synchronizer.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, sp, younger_sp} - - -// Layout of asm interpreter frame: -// -// 0xfffffff -// ...... -// [last extra incoming arg, (local # Nargs > 6 ? Nargs-1 : undef)] -// .. Note: incoming args are copied to local frame area upon entry -// [first extra incoming arg, (local # Nargs > 6 ? 6 : undef)] -// [6 words for C-arg storage (unused)] Are this and next one really needed? -// [C-aggregate-word (unused)] Yes, if want extra params to be in same place as C convention -// [16 words for register saving] <--- FP -// [interpreter_frame_vm_locals ] (see below) - -// Note: Llocals is always double-word aligned -// [first local i.e. local # 0] <-- Llocals -// ... -// [last local, i.e. local # Nlocals-1] - -// [monitors ] -// .... -// [monitors ] <-- Lmonitors (same as Llocals + 6*4 if none) -// (must be double-word aligned because -// monitor element size is constrained to -// doubleword) -// -// <-- Lesp (points 1 past TOS) -// [bottom word used for stack ] -// ... -// [top word used for stack] (first word of stack is double-word aligned) - -// [space for outgoing args (conservatively allocated as max_stack - 6 + interpreter_frame_extra_outgoing_argument_words)] -// [6 words for C-arg storage] -// [C-aggregate-word (unused)] -// [16 words for register saving] <--- SP -// ... -// 0x0000000 -// -// The in registers and local registers are preserved in a block at SP. -// -// The first six in registers (I0..I5) hold the first six locals. -// The locals are used as follows: -// Lesp first free element of expression stack -// (which grows towards __higher__ addresses) -// Lbcp is set to address of bytecode to execute -// It may at times (during GC) be an index instead. -// Lmethod the method being interpreted -// Llocals the base pointer for accessing the locals array -// (lower-numbered locals have lower addresses) -// Lmonitors the base pointer for accessing active monitors -// Lcache a saved pointer to the method's constant pool cache -// -// -// When calling out to another method, -// G5_method is set to method to call, G5_inline_cache_klass may be set, -// parameters are put in O registers, and also extra parameters -// must be cleverly copied from the top of stack to the outgoing param area in the frame, - -// All frames: - - public: - - enum { - // normal return address is 2 words past PC - pc_return_offset = 2 * BytesPerInstWord, - - // size of each block, in order of increasing address: - register_save_words = 16, - callee_aggregate_return_pointer_words = 0, - callee_register_argument_save_area_words = 6, - // memory_parameter_words = , - - // offset of each block, in order of increasing address: - // (note: callee_register_argument_save_area_words == Assembler::n_register_parameters) - register_save_words_sp_offset = 0, - callee_aggregate_return_pointer_sp_offset = register_save_words_sp_offset + register_save_words, - callee_register_argument_save_area_sp_offset = callee_aggregate_return_pointer_sp_offset + callee_aggregate_return_pointer_words, - memory_parameter_word_sp_offset = callee_register_argument_save_area_sp_offset + callee_register_argument_save_area_words, - varargs_offset = memory_parameter_word_sp_offset - }; - - private: - intptr_t* _younger_sp; // optional SP of callee (used to locate O7) - int _sp_adjustment_by_callee; // adjustment in words to SP by callee for making locals contiguous - - // Note: On SPARC, unlike Intel, the saved PC for a stack frame - // is stored at a __variable__ distance from that frame's SP. - // (In fact, it may be in the register save area of the callee frame, - // but that fact need not bother us.) Thus, we must store the - // address of that saved PC explicitly. On the other hand, SPARC - // stores the FP for a frame at a fixed offset from the frame's SP, - // so there is no need for a separate "frame::_fp" field. - - public: - // Accessors - - intptr_t* younger_sp() const { - assert(_younger_sp != NULL, "frame must possess a younger_sp"); - return _younger_sp; - } - - int callee_sp_adjustment() const { return _sp_adjustment_by_callee; } - void set_sp_adjustment_by_callee(int number_of_words) { _sp_adjustment_by_callee = number_of_words; } - - // Constructors - - // This constructor relies on the fact that the creator of a frame - // has flushed register windows which the frame will refer to, and - // that those register windows will not be reloaded until the frame is - // done reading and writing the stack. Moreover, if the "younger_sp" - // argument points into the register save area of the next younger - // frame (though it need not), the register window for that next - // younger frame must also stay flushed. (The caller is responsible - // for ensuring this.) - - frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_adjusted_stack = false); - - // make a deficient frame which doesn't know where its PC is: - enum unpatchable_t { unpatchable }; - frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL); - - void init(intptr_t* sp, address pc, CodeBlob* cb); - - // Walk from sp outward looking for old_sp, and return old_sp's predecessor - // (i.e. return the sp from the frame where old_sp is the fp). - // Register windows are assumed to be flushed for the stack in question. - - static intptr_t* next_younger_sp_or_null(intptr_t* old_sp, intptr_t* sp); - - // Return true if sp is a younger sp in the stack described by valid_sp. - static bool is_valid_stack_pointer(intptr_t* valid_sp, intptr_t* sp); - - public: - // accessors for the instance variables - intptr_t* fp() const { return (intptr_t*) ((intptr_t)(sp()[FP->sp_offset_in_saved_window()]) + STACK_BIAS ); } - - // All frames - - intptr_t* fp_addr_at(int index) const { return &fp()[index]; } - intptr_t* sp_addr_at(int index) const { return &sp()[index]; } - intptr_t fp_at( int index) const { return *fp_addr_at(index); } - intptr_t sp_at( int index) const { return *sp_addr_at(index); } - - private: - inline address* I7_addr() const; - inline address* O7_addr() const; - - inline address* I0_addr() const; - inline address* O0_addr() const; - intptr_t* younger_sp_addr_at(int index) const { return &younger_sp()[index]; } - - public: - // access to SPARC arguments and argument registers - - // Assumes reg is an in/local register - intptr_t* register_addr(Register reg) const { - return sp_addr_at(reg->sp_offset_in_saved_window()); - } - - // Assumes reg is an out register - intptr_t* out_register_addr(Register reg) const { - return younger_sp_addr_at(reg->after_save()->sp_offset_in_saved_window()); - } - - - // Interpreter frames - - public: - // Asm interpreter - enum interpreter_frame_vm_locals { - // 2 words, also used to save float regs across calls to C - interpreter_frame_d_scratch_fp_offset = -2, - interpreter_frame_l_scratch_fp_offset = -4, - interpreter_frame_mirror_offset = -5, // keep interpreted method alive - - interpreter_frame_oop_temp_offset = -6, // for native calls only - interpreter_frame_vm_locals_fp_offset = -6, // should be same as above, and should be zero mod 8 - - interpreter_frame_vm_local_words = -interpreter_frame_vm_locals_fp_offset, - - - // interpreter frame set-up needs to save 2 extra words in outgoing param area - // for class and jnienv arguments for native stubs (see nativeStubGen_sparc.cpp_ - - interpreter_frame_extra_outgoing_argument_words = 2 - }; - - enum compiler_frame_fixed_locals { - compiler_frame_vm_locals_fp_offset = -2 - }; - - private: - ConstantPoolCache** interpreter_frame_cpoolcache_addr() const; - - // where Lmonitors is saved: - inline BasicObjectLock** interpreter_frame_monitors_addr() const; - inline intptr_t** interpreter_frame_esp_addr() const; - - inline void interpreter_frame_set_tos_address(intptr_t* x); - - // monitors: - - // next two fns read and write Lmonitors value, - private: - BasicObjectLock* interpreter_frame_monitors() const; - void interpreter_frame_set_monitors(BasicObjectLock* monitors); - public: - - static jint interpreter_frame_expression_stack_direction() { return -1; } - -#endif // CPU_SPARC_FRAME_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/frame_sparc.inline.hpp b/src/hotspot/cpu/sparc/frame_sparc.inline.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/frame_sparc.inline.hpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_FRAME_SPARC_INLINE_HPP -#define CPU_SPARC_FRAME_SPARC_INLINE_HPP - -#include "asm/macroAssembler.hpp" -#include "code/vmreg.inline.hpp" -#include "utilities/align.hpp" - -// Inline functions for SPARC frames: - -// Constructors - -inline frame::frame() { - _pc = NULL; - _sp = NULL; - _younger_sp = NULL; - _cb = NULL; - _deopt_state = unknown; - _sp_adjustment_by_callee = 0; -} - -// Accessors: - -inline bool frame::equal(frame other) const { - bool ret = sp() == other.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(); } - -// 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 int frame::frame_size(RegisterMap* map) const { return sender_sp() - sp(); } - -inline intptr_t* frame::link() const { return (intptr_t *)(fp()[FP->sp_offset_in_saved_window()] + STACK_BIAS); } - -inline intptr_t* frame::unextended_sp() const { return sp() + _sp_adjustment_by_callee; } - -// return address: - -inline address frame::sender_pc() const { return *I7_addr() + pc_return_offset; } - -inline address* frame::I7_addr() const { return (address*) &sp()[ I7->sp_offset_in_saved_window()]; } -inline address* frame::I0_addr() const { return (address*) &sp()[ I0->sp_offset_in_saved_window()]; } - -inline address* frame::O7_addr() const { return (address*) &younger_sp()[ I7->sp_offset_in_saved_window()]; } -inline address* frame::O0_addr() const { return (address*) &younger_sp()[ I0->sp_offset_in_saved_window()]; } - -inline intptr_t* frame::sender_sp() const { return fp(); } - -inline intptr_t* frame::real_fp() const { return fp(); } - -inline intptr_t** frame::interpreter_frame_locals_addr() const { - return (intptr_t**) sp_addr_at( Llocals->sp_offset_in_saved_window()); -} - -inline intptr_t* frame::interpreter_frame_bcp_addr() const { - return (intptr_t*) sp_addr_at( Lbcp->sp_offset_in_saved_window()); -} - -inline intptr_t* frame::interpreter_frame_mdp_addr() const { - // %%%%% reinterpreting ImethodDataPtr as a mdx - return (intptr_t*) sp_addr_at( ImethodDataPtr->sp_offset_in_saved_window()); -} - -// bottom(base) of the expression stack (highest address) -inline intptr_t* frame::interpreter_frame_expression_stack() const { - return (intptr_t*)interpreter_frame_monitors() - 1; -} - -// top of expression stack (lowest address) -inline intptr_t* frame::interpreter_frame_tos_address() const { - return *interpreter_frame_esp_addr() + 1; -} - -inline BasicObjectLock** frame::interpreter_frame_monitors_addr() const { - return (BasicObjectLock**) sp_addr_at(Lmonitors->sp_offset_in_saved_window()); -} -inline intptr_t** frame::interpreter_frame_esp_addr() const { - return (intptr_t**)sp_addr_at(Lesp->sp_offset_in_saved_window()); -} - -inline void frame::interpreter_frame_set_tos_address( intptr_t* x ) { - *interpreter_frame_esp_addr() = x - 1; -} - -// monitor elements - -// in keeping with Intel side: end is lower in memory than begin; -// and beginning element is oldest element -// Also begin is one past last monitor. - -inline BasicObjectLock* frame::interpreter_frame_monitor_begin() const { - int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words, WordsPerLong); - return (BasicObjectLock *)fp_addr_at(-rounded_vm_local_words); -} - -inline BasicObjectLock* frame::interpreter_frame_monitor_end() const { - return interpreter_frame_monitors(); -} - - -inline void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) { - interpreter_frame_set_monitors(value); -} - -inline int frame::interpreter_frame_monitor_size() { - return align_up(BasicObjectLock::size(), WordsPerLong); -} - -inline Method** frame::interpreter_frame_method_addr() const { - return (Method**)sp_addr_at( Lmethod->sp_offset_in_saved_window()); -} - -inline BasicObjectLock* frame::interpreter_frame_monitors() const { - return *interpreter_frame_monitors_addr(); -} - -inline void frame::interpreter_frame_set_monitors(BasicObjectLock* monitors) { - *interpreter_frame_monitors_addr() = monitors; -} - -inline oop* frame::interpreter_frame_mirror_addr() const { - return (oop*)(fp() + interpreter_frame_mirror_offset); -} - -// Constant pool cache - -// where LcpoolCache is saved: -inline ConstantPoolCache** frame::interpreter_frame_cpoolcache_addr() const { - return (ConstantPoolCache**)sp_addr_at(LcpoolCache->sp_offset_in_saved_window()); - } - -inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { - return (ConstantPoolCache**)sp_addr_at( LcpoolCache->sp_offset_in_saved_window()); -} - -inline oop* frame::interpreter_frame_temp_oop_addr() const { - return (oop *)(fp() + interpreter_frame_oop_temp_offset); -} - - -inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const { - // note: adjust this code if the link argument in StubGenerator::call_stub() changes! - const Argument link = Argument(0, false); - return (JavaCallWrapper**)&sp()[link.as_in().as_register()->sp_offset_in_saved_window()]; -} - - -inline oop frame::saved_oop_result(RegisterMap* map) const { - return *((oop*) map->location(O0->as_VMReg())); -} - -inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { - *((oop*) map->location(O0->as_VMReg())) = obj; -} - -#endif // CPU_SPARC_FRAME_SPARC_INLINE_HPP diff --git a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Copyright (c) 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1BarrierSetAssembler.hpp" -#include "gc/g1/g1BarrierSetRuntime.hpp" -#include "gc/g1/g1CardTable.hpp" -#include "gc/g1/g1DirtyCardQueue.hpp" -#include "gc/g1/g1SATBMarkQueueSet.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" -#include "gc/g1/heapRegion.hpp" -#include "interpreter/interp_masm.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/macros.hpp" -#ifdef COMPILER1 -#include "c1/c1_LIRAssembler.hpp" -#include "c1/c1_MacroAssembler.hpp" -#include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif - -#define __ masm-> - -void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, - Register addr, Register count) { - bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; - // With G1, don't generate the call if we statically know that the target in uninitialized - if (!dest_uninitialized) { - Register tmp = O5; - assert_different_registers(addr, count, tmp); - Label filtered; - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ld(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldsb(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp); - } - // Is marking active? - __ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered); - - __ save_frame(0); - // Save the necessary global regs... will be used after. - if (addr->is_global()) { - __ mov(addr, L0); - } - if (count->is_global()) { - __ mov(count, L1); - } - __ mov(addr->after_save(), O0); - // Get the count into O1 - address slowpath = UseCompressedOops ? CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry) - : CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry); - __ call(slowpath); - __ delayed()->mov(count->after_save(), O1); - if (addr->is_global()) { - __ mov(L0, addr); - } - if (count->is_global()) { - __ mov(L1, count); - } - __ restore(); - - __ bind(filtered); - DEBUG_ONLY(__ set(0xDEADC0DE, tmp);) // we have killed tmp - } -} - -void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, - Register addr, Register count, Register tmp) { - // Get some new fresh output registers. - __ save_frame(0); - __ mov(addr->after_save(), O0); - __ call(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry)); - __ delayed()->mov(count->after_save(), O1); - __ restore(); -} - -#undef __ - -static address satb_log_enqueue_with_frame = NULL; -static u_char* satb_log_enqueue_with_frame_end = NULL; - -static address satb_log_enqueue_frameless = NULL; -static u_char* satb_log_enqueue_frameless_end = NULL; - -static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions? - -static void generate_satb_log_enqueue(bool with_frame) { - BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize); - CodeBuffer buf(bb); - MacroAssembler masm(&buf); - -#define __ masm. - - address start = __ pc(); - Register pre_val; - - Label refill, restart; - if (with_frame) { - __ save_frame(0); - pre_val = I0; // Was O0 before the save. - } else { - pre_val = O0; - } - - int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - assert(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t) && - in_bytes(SATBMarkQueue::byte_width_of_buf()) == sizeof(intptr_t), - "check sizes in assembly below"); - - __ bind(restart); - - // Load the index into the SATB buffer. SATBMarkQueue::_index is a size_t - // so ld_ptr is appropriate. - __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0); - - // index == 0? - __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill); - - __ ld_ptr(G2_thread, satb_q_buf_byte_offset, L1); - __ sub(L0, oopSize, L0); - - __ st_ptr(pre_val, L1, L0); // [_buf + index] := I0 - if (!with_frame) { - // Use return-from-leaf - __ retl(); - __ delayed()->st_ptr(L0, G2_thread, satb_q_index_byte_offset); - } else { - // Not delayed. - __ st_ptr(L0, G2_thread, satb_q_index_byte_offset); - } - if (with_frame) { - __ ret(); - __ delayed()->restore(); - } - __ bind(refill); - - address handle_zero = - CAST_FROM_FN_PTR(address, - &G1SATBMarkQueueSet::handle_zero_index_for_thread); - // This should be rare enough that we can afford to save all the - // scratch registers that the calling context might be using. - __ mov(G1_scratch, L0); - __ mov(G3_scratch, L1); - __ mov(G4, L2); - // We need the value of O0 above (for the write into the buffer), so we - // save and restore it. - __ mov(O0, L3); - // Since the call will overwrite O7, we save and restore that, as well. - __ mov(O7, L4); - __ call_VM_leaf(L5, handle_zero, G2_thread); - __ mov(L0, G1_scratch); - __ mov(L1, G3_scratch); - __ mov(L2, G4); - __ mov(L3, O0); - __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); - __ delayed()->mov(L4, O7); - - if (with_frame) { - satb_log_enqueue_with_frame = start; - satb_log_enqueue_with_frame_end = __ pc(); - } else { - satb_log_enqueue_frameless = start; - satb_log_enqueue_frameless_end = __ pc(); - } - -#undef __ -} - -#define __ masm-> - -void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, - Register obj, - Register index, - int offset, - Register pre_val, - Register tmp, - bool preserve_o_regs) { - Label filtered; - - if (obj == noreg) { - // We are not loading the previous value so make - // sure that we don't trash the value in pre_val - // with the code below. - assert_different_registers(pre_val, tmp); - } else { - // We will be loading the previous value - // in this code so... - assert(offset == 0 || index == noreg, "choose one"); - assert(pre_val == noreg, "check this code"); - } - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ld(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldsb(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp); - } - - // Is marking active? - __ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered); - - // Do we need to load the previous value? - if (obj != noreg) { - // Load the previous value... - if (index == noreg) { - if (Assembler::is_simm13(offset)) { - __ load_heap_oop(obj, offset, tmp); - } else { - __ set(offset, tmp); - __ load_heap_oop(obj, tmp, tmp); - } - } else { - __ load_heap_oop(obj, index, tmp); - } - // Previous value has been loaded into tmp - pre_val = tmp; - } - - assert(pre_val != noreg, "must have a real register"); - - // Is the previous value null? - __ cmp_and_brx_short(pre_val, G0, Assembler::equal, Assembler::pt, filtered); - - // OK, it's not filtered, so we'll need to call enqueue. In the normal - // case, pre_val will be a scratch G-reg, but there are some cases in - // which it's an O-reg. In the first case, do a normal call. In the - // latter, do a save here and call the frameless version. - - guarantee(pre_val->is_global() || pre_val->is_out(), - "Or we need to think harder."); - - if (pre_val->is_global() && !preserve_o_regs) { - __ call(satb_log_enqueue_with_frame); - __ delayed()->mov(pre_val, O0); - } else { - __ save_frame(0); - __ call(satb_log_enqueue_frameless); - __ delayed()->mov(pre_val->after_save(), O0); - __ restore(); - } - - __ bind(filtered); -} - -#undef __ - -static address dirty_card_log_enqueue = 0; -static u_char* dirty_card_log_enqueue_end = 0; - -// This gets to assume that o0 contains the object address. -static void generate_dirty_card_log_enqueue(CardTable::CardValue* byte_map_base) { - BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2); - CodeBuffer buf(bb); - MacroAssembler masm(&buf); -#define __ masm. - address start = __ pc(); - - Label not_already_dirty, restart, refill, young_card; - - __ srlx(O0, CardTable::card_shift, O0); - AddressLiteral addrlit(byte_map_base); - __ set(addrlit, O1); // O1 := - __ ldub(O0, O1, O2); // O2 := [O0 + O1] - - __ cmp_and_br_short(O2, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); - - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); - __ ldub(O0, O1, O2); // O2 := [O0 + O1] - - assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code"); - __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); - - __ bind(young_card); - // We didn't take the branch, so we're already dirty: return. - // Use return-from-leaf - __ retl(); - __ delayed()->nop(); - - // Not dirty. - __ bind(not_already_dirty); - - // Get O0 + O1 into a reg by itself - __ add(O0, O1, O3); - - // First, dirty it. - __ stb(G0, O3, G0); // [cardPtr] := 0 (i.e., dirty). - - int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - __ bind(restart); - - // Load the index into the update buffer. G1DirtyCardQueue::_index is - // a size_t so ld_ptr is appropriate here. - __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0); - - // index == 0? - __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill); - - __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, L1); - __ sub(L0, oopSize, L0); - - __ st_ptr(O3, L1, L0); // [_buf + index] := I0 - // Use return-from-leaf - __ retl(); - __ delayed()->st_ptr(L0, G2_thread, dirty_card_q_index_byte_offset); - - __ bind(refill); - address handle_zero = - CAST_FROM_FN_PTR(address, - &G1DirtyCardQueueSet::handle_zero_index_for_thread); - // This should be rare enough that we can afford to save all the - // scratch registers that the calling context might be using. - __ mov(G1_scratch, L3); - __ mov(G3_scratch, L5); - // We need the value of O3 above (for the write into the buffer), so we - // save and restore it. - __ mov(O3, L6); - // Since the call will overwrite O7, we save and restore that, as well. - __ mov(O7, L4); - - __ call_VM_leaf(L7_thread_cache, handle_zero, G2_thread); - __ mov(L3, G1_scratch); - __ mov(L5, G3_scratch); - __ mov(L6, O3); - __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); - __ delayed()->mov(L4, O7); - - dirty_card_log_enqueue = start; - dirty_card_log_enqueue_end = __ pc(); - // XXX Should have a guarantee here about not going off the end! - // Does it already do so? Do an experiment... - -#undef __ - -} - -#define __ masm-> - -void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) { - Label filtered; - MacroAssembler* post_filter_masm = masm; - - if (new_val == G0) return; - - G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); - - __ xor3(store_addr, new_val, tmp); - __ srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp); - - __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pt, filtered); - - // If the "store_addr" register is an "in" or "local" register, move it to - // a scratch reg so we can pass it as an argument. - bool use_scr = !(store_addr->is_global() || store_addr->is_out()); - // Pick a scratch register different from "tmp". - Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch); - // Make sure we use up the delay slot! - if (use_scr) { - post_filter_masm->mov(store_addr, scr); - } else { - post_filter_masm->nop(); - } - __ save_frame(0); - __ call(dirty_card_log_enqueue); - if (use_scr) { - __ delayed()->mov(scr, O0); - } else { - __ delayed()->mov(store_addr->after_save(), O0); - } - __ restore(); - - __ bind(filtered); -} - -void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp) { - bool in_heap = (decorators & IN_HEAP) != 0; - bool as_normal = (decorators & AS_NORMAL) != 0; - assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported"); - - bool needs_pre_barrier = as_normal; - // No need for post barrier if storing NULL - bool needs_post_barrier = val != G0 && in_heap; - - bool is_array = (decorators & IS_ARRAY) != 0; - bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; - bool precise = is_array || on_anonymous; - - Register index = dst.has_index() ? dst.index() : noreg; - int disp = dst.has_disp() ? dst.disp() : 0; - - if (needs_pre_barrier) { - // Load and record the previous value. - g1_write_barrier_pre(masm, dst.base(), index, disp, - noreg /* pre_val */, - tmp, true /*preserve_o_regs*/); - } - - Register new_val = val; - if (needs_post_barrier) { - // G1 barrier needs uncompressed oop for region cross check. - if (UseCompressedOops && val != G0) { - new_val = tmp; - __ mov(val, new_val); - } - } - - BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp); - - if (needs_post_barrier) { - Register base = dst.base(); - if (precise) { - if (!dst.has_index()) { - __ add(base, disp, base); - } else { - assert(!dst.has_disp(), "not supported yet"); - __ add(base, index, base); - } - } - g1_write_barrier_post(masm, base, new_val, tmp); - } -} - -void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address src, Register dst, Register tmp) { - bool on_oop = is_reference_type(type); - bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; - bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; - bool on_reference = on_weak || on_phantom; - // Load the value of the referent field. - ModRefBarrierSetAssembler::load_at(masm, decorators, type, src, dst, tmp); - if (on_oop && on_reference) { - // Generate the G1 pre-barrier code to log the value of - // the referent field in an SATB buffer. Note with - // these parameters the pre-barrier does not generate - // the load of the previous value - - Register pre_val = dst; - bool saved = false; - if (pre_val->is_in()) { - // The g1_write_barrier_pre method assumes that the pre_val - // is not in an input register. - __ save_frame_and_mov(0, pre_val, O0); - pre_val = O0; - saved = true; - } - - g1_write_barrier_pre(masm, noreg /* obj */, noreg /* index */, 0 /* offset */, - pre_val /* pre_val */, - tmp /* tmp */, - true /* preserve_o_regs */); - - if (saved) { - __ restore(); - } - } -} - -void G1BarrierSetAssembler::barrier_stubs_init() { - if (dirty_card_log_enqueue == 0) { - G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); - CardTable *ct = bs->card_table(); - generate_dirty_card_log_enqueue(ct->byte_map_base()); - assert(dirty_card_log_enqueue != 0, "postcondition."); - } - if (satb_log_enqueue_with_frame == 0) { - generate_satb_log_enqueue(true); - assert(satb_log_enqueue_with_frame != 0, "postcondition."); - } - if (satb_log_enqueue_frameless == 0) { - generate_satb_log_enqueue(false); - assert(satb_log_enqueue_frameless != 0, "postcondition."); - } -} - -#ifdef COMPILER1 - -#undef __ -#define __ ce->masm()-> - -void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { - G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); - // 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(*stub->entry()); - - assert(stub->pre_val()->is_register(), "Precondition."); - Register pre_val_reg = stub->pre_val()->as_register(); - - if (stub->do_load()) { - ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /*wide*/, false /*unaligned*/); - } - - if (__ is_in_wdisp16_range(*stub->continuation())) { - __ br_null(pre_val_reg, /*annul*/false, Assembler::pt, *stub->continuation()); - } else { - __ cmp(pre_val_reg, G0); - __ brx(Assembler::equal, false, Assembler::pn, *stub->continuation()); - } - __ delayed()->nop(); - - __ call(bs->pre_barrier_c1_runtime_code_blob()->code_begin()); - __ delayed()->mov(pre_val_reg, G4); - __ br(Assembler::always, false, Assembler::pt, *stub->continuation()); - __ delayed()->nop(); -} - -void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { - G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); - __ bind(*stub->entry()); - - assert(stub->addr()->is_register(), "Precondition."); - assert(stub->new_val()->is_register(), "Precondition."); - Register addr_reg = stub->addr()->as_pointer_register(); - Register new_val_reg = stub->new_val()->as_register(); - - if (__ is_in_wdisp16_range(*stub->continuation())) { - __ br_null(new_val_reg, /*annul*/false, Assembler::pt, *stub->continuation()); - } else { - __ cmp(new_val_reg, G0); - __ brx(Assembler::equal, false, Assembler::pn, *stub->continuation()); - } - __ delayed()->nop(); - - __ call(bs->post_barrier_c1_runtime_code_blob()->code_begin()); - __ delayed()->mov(addr_reg, G4); - __ br(Assembler::always, false, Assembler::pt, *stub->continuation()); - __ delayed()->nop(); -} - -#undef __ -#define __ sasm-> - -void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { - __ prologue("g1_pre_barrier", false); - - // G4: previous value of memory - - Register pre_val = G4; - Register tmp = G1_scratch; - Register tmp2 = G3_scratch; - - Label refill, restart; - int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ld(G2_thread, satb_q_active_byte_offset, tmp); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldsb(G2_thread, satb_q_active_byte_offset, tmp); - } - __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart); - __ retl(); - __ delayed()->nop(); - - __ bind(restart); - // Load the index into the SATB buffer. SATBMarkQueue::_index is a - // size_t so ld_ptr is appropriate - __ ld_ptr(G2_thread, satb_q_index_byte_offset, tmp); - - // index == 0? - __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pn, refill); - - __ ld_ptr(G2_thread, satb_q_buf_byte_offset, tmp2); - __ sub(tmp, oopSize, tmp); - - __ st_ptr(pre_val, tmp2, tmp); // [_buf + index] := - // Use return-from-leaf - __ retl(); - __ delayed()->st_ptr(tmp, G2_thread, satb_q_index_byte_offset); - - __ bind(refill); - - __ save_live_registers_no_oop_map(true); - - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, - G1SATBMarkQueueSet::handle_zero_index_for_thread), - G2_thread); - - __ restore_live_registers(true); - - __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); - __ epilogue(); -} - -void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { - __ prologue("g1_post_barrier", false); - - G1BarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); - - Register addr = G4; - Register cardtable = G5; - Register tmp = G1_scratch; - Register tmp2 = G3_scratch; - CardTable::CardValue* byte_map_base = bs->card_table()->byte_map_base(); - - Label not_already_dirty, restart, refill, young_card; - -#ifdef _LP64 - __ srlx(addr, CardTable::card_shift, addr); -#else - __ srl(addr, CardTable::card_shift, addr); -#endif - - AddressLiteral rs((address)byte_map_base); - __ set(rs, cardtable); // cardtable := - __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] - - __ cmp_and_br_short(tmp, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card); - - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); - __ ldub(addr, cardtable, tmp); // tmp := [addr + cardtable] - - assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code"); - __ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, not_already_dirty); - - __ bind(young_card); - // We didn't take the branch, so we're already dirty: return. - // Use return-from-leaf - __ retl(); - __ delayed()->nop(); - - // Not dirty. - __ bind(not_already_dirty); - - // Get cardtable + tmp into a reg by itself - __ add(addr, cardtable, tmp2); - - // First, dirty it. - __ stb(G0, tmp2, 0); // [cardPtr] := 0 (i.e., dirty). - - Register tmp3 = cardtable; - Register tmp4 = tmp; - - // these registers are now dead - addr = cardtable = tmp = noreg; - - int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - - __ bind(restart); - - // Get the index into the update buffer. G1DirtyCardQueue::_index is - // a size_t so ld_ptr is appropriate here. - __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, tmp3); - - // index == 0? - __ cmp_and_brx_short(tmp3, G0, Assembler::equal, Assembler::pn, refill); - - __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, tmp4); - __ sub(tmp3, oopSize, tmp3); - - __ st_ptr(tmp2, tmp4, tmp3); // [_buf + index] := - // Use return-from-leaf - __ retl(); - __ delayed()->st_ptr(tmp3, G2_thread, dirty_card_q_index_byte_offset); - - __ bind(refill); - - __ save_live_registers_no_oop_map(true); - - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, - G1DirtyCardQueueSet::handle_zero_index_for_thread), - G2_thread); - - __ restore_live_registers(true); - - __ br(Assembler::always, /*annul*/false, Assembler::pt, restart); - __ epilogue(); -} - -#undef __ - -#endif // COMPILER1 diff --git a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#ifndef CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP -#define CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP - -#include "asm/macroAssembler.hpp" -#include "gc/shared/modRefBarrierSetAssembler.hpp" -#include "utilities/macros.hpp" - -class LIR_Assembler; -class StubAssembler; -class G1PreBarrierStub; -class G1PostBarrierStub; - -class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { -protected: - virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count); - virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp); - - void g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs); - void g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp); - - virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp); - -public: -#ifdef COMPILER1 - void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); - void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); - - void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); - void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); -#endif - - virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address src, Register dst, Register tmp); - virtual void barrier_stubs_init(); -}; - -#endif // CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/barrierSetAssembler.hpp" -#include "interpreter/interp_masm.hpp" -#include "runtime/jniHandles.hpp" - -#define __ masm-> - -void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp) { - bool in_heap = (decorators & IN_HEAP) != 0; - bool in_native = (decorators & IN_NATIVE) != 0; - bool is_not_null = (decorators & IS_NOT_NULL) != 0; - - switch (type) { - case T_ARRAY: - case T_OBJECT: { - if (in_heap) { - if (dst.has_disp() && !Assembler::is_simm13(dst.disp())) { - assert(!dst.has_index(), "not supported yet"); - __ set(dst.disp(), tmp); - dst = Address(dst.base(), tmp); - } - if (UseCompressedOops) { - assert(dst.base() != val, "not enough registers"); - if (is_not_null) { - __ encode_heap_oop_not_null(val); - } else { - __ encode_heap_oop(val); - } - __ st(val, dst); - } else { - __ st_ptr(val, dst); - } - } else { - assert(in_native, "why else?"); - __ st_ptr(val, dst); - } - break; - } - default: Unimplemented(); - } -} - -void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address src, Register dst, Register tmp) { - bool in_heap = (decorators & IN_HEAP) != 0; - bool in_native = (decorators & IN_NATIVE) != 0; - bool is_not_null = (decorators & IS_NOT_NULL) != 0; - - switch (type) { - case T_ARRAY: - case T_OBJECT: { - if (in_heap) { - if (src.has_disp() && !Assembler::is_simm13(src.disp())) { - assert(!src.has_index(), "not supported yet"); - __ set(src.disp(), tmp); - src = Address(src.base(), tmp); - } - if (UseCompressedOops) { - __ lduw(src, dst); - if (is_not_null) { - __ decode_heap_oop_not_null(dst); - } else { - __ decode_heap_oop(dst); - } - } else { - __ ld_ptr(src, dst); - } - } else { - assert(in_native, "why else?"); - __ ld_ptr(src, dst); - } - break; - } - default: Unimplemented(); - } -} - -void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, - Register obj, Register tmp, Label& slowpath) { - __ andn(obj, JNIHandles::weak_tag_mask, obj); - __ ld_ptr(obj, 0, obj); -} diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#ifndef CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP -#define CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP - -#include "asm/macroAssembler.hpp" -#include "memory/allocation.hpp" -#include "oops/access.hpp" - -class InterpreterMacroAssembler; - -class BarrierSetAssembler: public CHeapObj { -public: - virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count) {} - virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count) {} - - virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Address dst, Register tmp); - - virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address src, Register dst, Register tmp); - - // Support for jniFastGetField to try resolving a jobject/jweak in native - virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, - Register obj, Register tmp, Label& slowpath); - - virtual void barrier_stubs_init() {} -}; - -#endif // CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "gc/shared/barrierSetNMethod.hpp" -#include "utilities/debug.hpp" - -void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { - ShouldNotReachHere(); -} - -void BarrierSetNMethod::disarm(nmethod* nm) { - ShouldNotReachHere(); -} - -bool BarrierSetNMethod::is_armed(nmethod* nm) { - ShouldNotReachHere(); - return false; -} diff --git a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/cardTable.hpp" -#include "gc/shared/cardTableBarrierSet.hpp" -#include "gc/shared/cardTableBarrierSetAssembler.hpp" -#include "interpreter/interp_masm.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 CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, - Register addr, Register count, Register tmp) { - CardTableBarrierSet* ctbs = barrier_set_cast(BarrierSet::barrier_set()); - CardTable* ct = ctbs->card_table(); - assert_different_registers(addr, count, tmp); - - Label L_loop, L_done; - - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_done); // zero count - nothing to do - - __ sll_ptr(count, LogBytesPerHeapOop, count); - __ sub(count, BytesPerHeapOop, count); - __ add(count, addr, count); - // Use two shifts to clear out those low order two bits! (Cannot opt. into 1.) - __ srl_ptr(addr, CardTable::card_shift, addr); - __ srl_ptr(count, CardTable::card_shift, count); - __ sub(count, addr, count); - AddressLiteral rs(ct->byte_map_base()); - __ set(rs, tmp); - __ BIND(L_loop); - __ stb(G0, tmp, addr); - __ subcc(count, 1, count); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); - __ delayed()->add(addr, 1, addr); - - __ BIND(L_done); -} - -void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm, - CardTable::CardValue* byte_map_base, - Register tmp, Register obj) { - __ srlx(obj, CardTable::card_shift, obj); - assert(tmp != obj, "need separate temp reg"); - __ set((address) byte_map_base, tmp); - __ stb(G0, tmp, obj); -} - -void CardTableBarrierSetAssembler::card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) { - // If we're writing constant NULL, we can skip the write barrier. - if (new_val == G0) return; - CardTableBarrierSet* bs = barrier_set_cast(BarrierSet::barrier_set()); - card_table_write(masm, bs->card_table()->byte_map_base(), tmp, store_addr); -} - -void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp) { - bool in_heap = (decorators & IN_HEAP) != 0; - - bool is_array = (decorators & IS_ARRAY) != 0; - bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; - bool precise = is_array || on_anonymous; - - // No need for post barrier if storing NULL - bool needs_post_barrier = val != G0 && in_heap; - - BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp); - if (needs_post_barrier) { - Register base = dst.base(); - if (precise) { - if (!dst.has_index()) { - __ add(base, dst.disp(), base); - } else { - assert(!dst.has_disp(), "not supported yet"); - __ add(base, dst.index(), base); - } - } - card_write_barrier_post(masm, base, val, tmp); - } -} diff --git a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#ifndef CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP -#define CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP - -#include "asm/macroAssembler.hpp" -#include "gc/shared/cardTable.hpp" -#include "gc/shared/modRefBarrierSetAssembler.hpp" - -class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler { -protected: - virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, - Register addr, Register count, Register tmp); - - void card_table_write(MacroAssembler* masm, CardTable::CardValue* byte_map_base, Register tmp, Register obj); - - void card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp); - - virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp); -}; - -#endif // CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp b/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2018, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/modRefBarrierSetAssembler.hpp" - -#define __ masm-> - -void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count) { - if (type == T_OBJECT) { - bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; - if (!checkcast) { - // save arguments for barrier generation - __ mov(dst, G1); - __ mov(count, G5); - gen_write_ref_array_pre_barrier(masm, decorators, G1, G5); - } else { - gen_write_ref_array_pre_barrier(masm, decorators, dst, count); - } - } -} - -void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count) { - if (type == T_OBJECT) { - bool checkcast = (decorators & ARRAYCOPY_CHECKCAST) != 0; - if (!checkcast) { - // O0 is used as temp register - gen_write_ref_array_post_barrier(masm, decorators, G1, G5, O0); - } else { - gen_write_ref_array_post_barrier(masm, decorators, dst, count, O3); - } - } -} - -void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp) { - if (is_reference_type(type)) { - oop_store_at(masm, decorators, type, val, dst, tmp); - } else { - BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp); - } -} diff --git a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp b/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - */ - -#ifndef CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP -#define CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP - -#include "asm/macroAssembler.hpp" -#include "gc/shared/barrierSetAssembler.hpp" - -// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other -// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected -// accesses, which are overridden in the concrete BarrierSetAssembler. - -class ModRefBarrierSetAssembler: public BarrierSetAssembler { -protected: - virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, - Register addr, Register count) {} - virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, - Register addr, Register count, Register tmp) {} - - virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp) = 0; -public: - virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count); - virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register src, Register dst, Register count); - - virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Register val, Address dst, Register tmp); -}; - -#endif // CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp b/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/globalDefinitions_sparc.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 1999, 2020, 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. - * - */ - -#ifndef CPU_SPARC_GLOBALDEFINITIONS_SPARC_HPP -#define CPU_SPARC_GLOBALDEFINITIONS_SPARC_HPP - -// Size of Sparc Instructions -const int BytesPerInstWord = 4; - -const int StackAlignmentInBytes = (2*wordSize); - -// Indicates whether the C calling conventions require that -// 32-bit integer argument values are extended to 64 bits. -const bool CCallingConventionRequiresIntsAsLongs = true; - -#define SUPPORTS_NATIVE_CX8 - -#define CPU_MULTI_COPY_ATOMIC - -// The expected size in bytes of a cache line, used to pad data structures. -#if defined(TIERED) - // tiered, 64-bit, large machine - #define DEFAULT_CACHE_LINE_SIZE 128 - #define OM_CACHE_LINE_SIZE 64 -#elif defined(COMPILER1) - // pure C1, 32-bit, small machine - #define DEFAULT_CACHE_LINE_SIZE 16 -#elif defined(COMPILER2) - // pure C2, 64-bit, large machine - #define DEFAULT_CACHE_LINE_SIZE 128 - #define OM_CACHE_LINE_SIZE 64 -#endif - -#if defined(SOLARIS) -#define SUPPORT_RESERVED_STACK_AREA -#endif - -#endif // CPU_SPARC_GLOBALDEFINITIONS_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/globals_sparc.hpp b/src/hotspot/cpu/sparc/globals_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/globals_sparc.hpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2000, 2020, 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. - * - */ - -#ifndef CPU_SPARC_GLOBALS_SPARC_HPP -#define CPU_SPARC_GLOBALS_SPARC_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) - -// For sparc we do not do call backs when a thread is in the interpreter, because the -// interpreter dispatch needs at least two instructions - first to load the dispatch address -// in a register, and second to jmp. The swapping of the dispatch table may occur _after_ -// the load of the dispatch address and hence the jmp would still go to the location -// according to the prior table. So, we let the thread continue and let it block by itself. -define_pd_global(bool, DontYieldALot, true); // yield no more than 100 times per second - -define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks -define_pd_global(bool, TrapBasedNullChecks, false); // Not needed on sparc. -define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs passed to check cast - -define_pd_global(uintx, CodeCacheSegmentSize, 64 TIERED_ONLY(+64)); // Tiered compilation has large code-entry alignment. -define_pd_global(intx, CodeEntryAlignment, 32); -// The default setting 16/16 seems to work best. -// (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.) -define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize -define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC -define_pd_global(intx, InlineSmallCode, 1500); - -#define DEFAULT_STACK_YELLOW_PAGES (2) -#define DEFAULT_STACK_RED_PAGES (1) -#define DEFAULT_STACK_RESERVED_PAGES (SOLARIS_ONLY(1) NOT_SOLARIS(0)) - -define_pd_global(intx, CompilerThreadStackSize, 1024); -define_pd_global(intx, ThreadStackSize, 1024); -define_pd_global(intx, VMThreadStackSize, 1024); -#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2)) - -#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES -#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES -#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES -#define MIN_STACK_RESERVED_PAGES (0) - -define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); -define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); -define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); -define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); - -define_pd_global(bool, RewriteBytecodes, true); -define_pd_global(bool, RewriteFrequentPairs, true); - -define_pd_global(bool, PreserveFramePointer, false); - -define_pd_global(uintx, TypeProfileLevel, 111); - -define_pd_global(bool, CompactStrings, true); - -define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); - -#define ARCH_FLAGS(develop, \ - product, \ - diagnostic, \ - experimental, \ - notproduct, \ - range, \ - constraint) \ - \ - product(intx, UseVIS, 99, \ - "Highest supported VIS instructions set on SPARC") \ - range(0, 99) \ - \ - product(bool, UseCBCond, false, \ - "Use compare and branch instruction on SPARC") \ - \ - product(bool, UseMPMUL, false, \ - "Use multi-precision multiply instruction (mpmul) on SPARC") \ - \ - product(bool, UseBlockZeroing, false, \ - "Use special cpu instructions for block zeroing") \ - \ - product(intx, BlockZeroingLowLimit, 2048, \ - "Minimum size in bytes when block zeroing will be used") \ - range(1, max_jint) \ - \ - product(bool, UseBlockCopy, false, \ - "Use special cpu instructions for block copy") \ - \ - product(intx, BlockCopyLowLimit, 2048, \ - "Minimum size in bytes when block copy will be used") \ - range(1, max_jint) \ - \ - product(bool, UseNiagaraInstrs, false, \ - "Use Niagara-efficient instruction subset") \ - \ - develop(bool, UseCASForSwap, false, \ - "Do not use swap instructions, but only CAS (in a loop) on SPARC")\ - \ - product(uintx, ArraycopySrcPrefetchDistance, 0, \ - "Distance to prefetch source array in arraycopy") \ - constraint(ArraycopySrcPrefetchDistanceConstraintFunc, AfterErgo) \ - \ - product(uintx, ArraycopyDstPrefetchDistance, 0, \ - "Distance to prefetch destination array in arraycopy") \ - constraint(ArraycopyDstPrefetchDistanceConstraintFunc, AfterErgo) \ - -#endif // CPU_SPARC_GLOBALS_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/icBuffer_sparc.cpp b/src/hotspot/cpu/sparc/icBuffer_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/icBuffer_sparc.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 1997, 2017, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/icBuffer.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "interpreter/bytecodes.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_sparc.hpp" -#include "oops/oop.inline.hpp" - -int InlineCacheBuffer::ic_stub_code_size() { - return (NativeMovConstReg::instruction_size + // sethi;add - NativeJump::instruction_size + // sethi; jmp; delay slot - (1*BytesPerInstWord) + 1); // flush + 1 extra byte -} - -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 metadata, we do not need reloc info - // because - // (1) the metadata is old (i.e., doesn't matter for scavenges) - // (2) these ICStubs are removed *before* a GC happens, so the roots disappear - AddressLiteral cached_value_addrlit((address)cached_value, relocInfo::none); - // Force the set to generate the fixed sequence so next_instruction_address works - masm->patchable_set(cached_value_addrlit, G5_inline_cache_reg); - assert(G3_scratch != G5_method, "Do not clobber the method oop in the transition stub"); - assert(G3_scratch != G5_inline_cache_reg, "Do not clobber the inline cache register in the transition stub"); - AddressLiteral entry(entry_point); - masm->JUMP(entry, G3_scratch, 0); - masm->delayed()->nop(); - masm->flush(); -} - - -address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - NativeJump* jump = nativeJump_at(move->next_instruction_address()); - return jump->jump_destination(); -} - - -void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { - NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object - NativeJump* jump = nativeJump_at(move->next_instruction_address()); - void* o = (void*)move->data(); - return o; -} diff --git a/src/hotspot/cpu/sparc/icache_sparc.cpp b/src/hotspot/cpu/sparc/icache_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/icache_sparc.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 1997, 2010, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "runtime/icache.hpp" - -#define __ _masm-> - -void ICacheStubGenerator::generate_icache_flush( - ICache::flush_icache_stub_t* flush_icache_stub -) { - StubCodeMark mark(this, "ICache", "flush_icache_stub"); - address start = __ pc(); - - Label L; - __ bind(L); - __ flush( O0, G0 ); - __ deccc( O1 ); - __ br(Assembler::positive, false, Assembler::pn, L); - __ delayed()->inc( O0, 8 ); - __ retl(false); - __ delayed()->mov( O2, O0 ); // handshake with caller to make sure it happened! - - // Must be set here so StubCodeMark destructor can call the flush stub. - *flush_icache_stub = (ICache::flush_icache_stub_t)start; -}; - -#undef __ diff --git a/src/hotspot/cpu/sparc/icache_sparc.hpp b/src/hotspot/cpu/sparc/icache_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/icache_sparc.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_ICACHE_SPARC_HPP -#define CPU_SPARC_ICACHE_SPARC_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: - enum { - stub_size = 160, // Size of the icache flush stub in bytes - line_size = 8, // flush instruction affects a dword - log2_line_size = 3 // log2(line_size) - }; - - // Use default implementation -}; - -#endif // CPU_SPARC_ICACHE_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp b/src/hotspot/cpu/sparc/interp_masm_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp +++ /dev/null @@ -1,2650 +0,0 @@ -/* - * Copyright (c) 1997, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interp_masm_sparc.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "logging/log.hpp" -#include "oops/arrayOop.hpp" -#include "oops/markWord.hpp" -#include "oops/methodData.hpp" -#include "oops/method.hpp" -#include "oops/methodCounters.hpp" -#include "prims/jvmtiExport.hpp" -#include "prims/jvmtiThreadState.hpp" -#include "runtime/basicLock.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/thread.inline.hpp" -#include "utilities/align.hpp" -#include "utilities/powerOfTwo.hpp" - -// Implementation of InterpreterMacroAssembler - -// This file specializes the assember with interpreter-specific macros - -const Address InterpreterMacroAssembler::l_tmp(FP, (frame::interpreter_frame_l_scratch_fp_offset * wordSize) + STACK_BIAS); -const Address InterpreterMacroAssembler::d_tmp(FP, (frame::interpreter_frame_d_scratch_fp_offset * wordSize) + STACK_BIAS); - -void InterpreterMacroAssembler::jump_to_entry(address entry) { - assert(entry, "Entry must have been generated by now"); - AddressLiteral al(entry); - jump_to(al, G3_scratch); - delayed()->nop(); -} - -void InterpreterMacroAssembler::compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta) { - // Note: this algorithm is also used by C1's OSR entry sequence. - // Any changes should also be applied to CodeEmitter::emit_osr_entry(). - assert_different_registers(args_size, locals_size); - // max_locals*2 for TAGS. Assumes that args_size has already been adjusted. - subcc(locals_size, args_size, delta);// extra space for non-arguments locals in words - // Use br/mov combination because it works on both V8 and V9 and is - // faster. - Label skip_move; - br(Assembler::negative, true, Assembler::pt, skip_move); - delayed()->mov(G0, delta); - bind(skip_move); - align_up(delta, WordsPerLong); // make multiple of 2 (SP must be 2-word aligned) - sll(delta, LogBytesPerWord, delta); // extra space for locals in bytes -} - -// Dispatch code executed in the prolog of a bytecode which does not do it's -// own dispatch. The dispatch address is computed and placed in IdispatchAddress -void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) { - assert_not_delayed(); - ldub( Lbcp, bcp_incr, Lbyte_code); // load next bytecode - // dispatch table to use - AddressLiteral tbl(Interpreter::dispatch_table(state)); - sll(Lbyte_code, LogBytesPerWord, Lbyte_code); // multiply by wordSize - set(tbl, G3_scratch); // compute addr of table - ld_ptr(G3_scratch, Lbyte_code, IdispatchAddress); // get entry addr -} - - -// Dispatch code executed in the epilog of a bytecode which does not do it's -// own dispatch. The dispatch address in IdispatchAddress is used for the -// dispatch. -void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) { - assert_not_delayed(); - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); - jmp( IdispatchAddress, 0 ); - if (bcp_incr != 0) delayed()->inc(Lbcp, bcp_incr); - else delayed()->nop(); -} - -void InterpreterMacroAssembler::dispatch_next(TosState state, int bcp_incr, bool generate_poll) { - // %%%% consider branching to a single shared dispatch stub (for each bcp_incr) - assert_not_delayed(); - ldub( Lbcp, bcp_incr, Lbyte_code); // load next bytecode - dispatch_Lbyte_code(state, Interpreter::dispatch_table(state), bcp_incr, true, generate_poll); -} - - -void InterpreterMacroAssembler::dispatch_next_noverify_oop(TosState state, int bcp_incr) { - // %%%% consider branching to a single shared dispatch stub (for each bcp_incr) - assert_not_delayed(); - ldub( Lbcp, bcp_incr, Lbyte_code); // load next bytecode - dispatch_Lbyte_code(state, Interpreter::dispatch_table(state), bcp_incr, false); -} - - -void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { - // load current bytecode - assert_not_delayed(); - ldub( Lbcp, 0, Lbyte_code); // load next bytecode - dispatch_base(state, table); -} - - -void InterpreterMacroAssembler::call_VM_leaf_base( - Register java_thread, - address entry_point, - int number_of_arguments -) { - if (!java_thread->is_valid()) - java_thread = L7_thread_cache; - // super call - MacroAssembler::call_VM_leaf_base(java_thread, entry_point, number_of_arguments); -} - - -void InterpreterMacroAssembler::call_VM_base( - Register oop_result, - Register java_thread, - Register last_java_sp, - address entry_point, - int number_of_arguments, - bool check_exception -) { - if (!java_thread->is_valid()) - java_thread = L7_thread_cache; - // See class ThreadInVMfromInterpreter, which assumes that the interpreter - // takes responsibility for setting its own thread-state on call-out. - // However, ThreadInVMfromInterpreter resets the state to "in_Java". - - //save_bcp(); // save bcp - MacroAssembler::call_VM_base(oop_result, java_thread, last_java_sp, entry_point, number_of_arguments, check_exception); - //restore_bcp(); // restore bcp - //restore_locals(); // restore locals pointer -} - - -void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) { - if (JvmtiExport::can_pop_frame()) { - Label L; - - // Check the "pending popframe condition" flag in the current thread - ld(G2_thread, JavaThread::popframe_condition_offset(), scratch_reg); - - // Initiate popframe handling only if it is not already being processed. If the flag - // has the popframe_processing bit set, it means that this code is called *during* popframe - // handling - we don't want to reenter. - btst(JavaThread::popframe_pending_bit, scratch_reg); - br(zero, false, pt, L); - delayed()->nop(); - btst(JavaThread::popframe_processing_bit, scratch_reg); - br(notZero, false, pt, L); - delayed()->nop(); - - // Call Interpreter::remove_activation_preserving_args_entry() to get the - // address of the same-named entrypoint in the generated interpreter code. - call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); - - // Jump to Interpreter::_remove_activation_preserving_args_entry - jmpl(O0, G0, G0); - delayed()->nop(); - bind(L); - } -} - - -void InterpreterMacroAssembler::load_earlyret_value(TosState state) { - Register thr_state = G4_scratch; - ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), thr_state); - const Address tos_addr(thr_state, JvmtiThreadState::earlyret_tos_offset()); - const Address oop_addr(thr_state, JvmtiThreadState::earlyret_oop_offset()); - const Address val_addr(thr_state, JvmtiThreadState::earlyret_value_offset()); - switch (state) { - case ltos: ld_long(val_addr, Otos_l); break; - case atos: ld_ptr(oop_addr, Otos_l); - st_ptr(G0, oop_addr); break; - case btos: // fall through - case ztos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: ld(val_addr, Otos_l1); break; - case ftos: ldf(FloatRegisterImpl::S, val_addr, Ftos_f); break; - case dtos: ldf(FloatRegisterImpl::D, val_addr, Ftos_d); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } - // Clean up tos value in the jvmti thread state - or3(G0, ilgl, G3_scratch); - stw(G3_scratch, tos_addr); - st_long(G0, val_addr); - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); -} - - -void InterpreterMacroAssembler::check_and_handle_earlyret(Register scratch_reg) { - if (JvmtiExport::can_force_early_return()) { - Label L; - Register thr_state = G3_scratch; - ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), thr_state); - br_null_short(thr_state, pt, L); // if (thread->jvmti_thread_state() == NULL) exit; - - // Initiate earlyret handling only if it is not already being processed. - // If the flag has the earlyret_processing bit set, it means that this code - // is called *during* earlyret handling - we don't want to reenter. - ld(thr_state, JvmtiThreadState::earlyret_state_offset(), G4_scratch); - cmp_and_br_short(G4_scratch, JvmtiThreadState::earlyret_pending, Assembler::notEqual, pt, L); - - // Call Interpreter::remove_activation_early_entry() to get the address of the - // same-named entrypoint in the generated interpreter code - ld(thr_state, JvmtiThreadState::earlyret_tos_offset(), Otos_l1); - call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), Otos_l1); - - // Jump to Interpreter::_remove_activation_early_entry - jmpl(O0, G0, G0); - delayed()->nop(); - bind(L); - } -} - - -void InterpreterMacroAssembler::super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) { - mov(arg_1, O0); - mov(arg_2, O1); - MacroAssembler::call_VM_leaf_base(thread_cache, entry_point, 2); -} - -void InterpreterMacroAssembler::dispatch_base(TosState state, address* table) { - assert_not_delayed(); - dispatch_Lbyte_code(state, table); -} - - -void InterpreterMacroAssembler::dispatch_normal(TosState state) { - dispatch_base(state, Interpreter::normal_table(state)); -} - - -void InterpreterMacroAssembler::dispatch_only(TosState state) { - dispatch_base(state, Interpreter::dispatch_table(state)); -} - - -// common code to dispatch and dispatch_only -// dispatch value in Lbyte_code and increment Lbcp - -void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, address* table, int bcp_incr, bool verify, bool generate_poll) { - // %%%%% maybe implement +VerifyActivationFrameSize here - //verify_thread(); //too slow; we will just verify on method entry & exit - if (verify) interp_verify_oop(Otos_i, state, __FILE__, __LINE__); - // dispatch table to use - AddressLiteral tbl(table); - Label dispatch; - - if (generate_poll) { - AddressLiteral sfpt_tbl(Interpreter::safept_table(state)); - Label no_safepoint; - - if (tbl.value() != sfpt_tbl.value()) { - ldx(Address(G2_thread, Thread::polling_page_offset()), G3_scratch, 0); - // Armed page has poll_bit set, if poll bit is cleared just continue. - and3(G3_scratch, SafepointMechanism::poll_bit(), G3_scratch); - - br_null_short(G3_scratch, Assembler::pt, no_safepoint); - set(sfpt_tbl, G3_scratch); - ba_short(dispatch); - } - bind(no_safepoint); - } - - set(tbl, G3_scratch); // compute addr of table - bind(dispatch); - sll(Lbyte_code, LogBytesPerWord, Lbyte_code); // multiply by wordSize - ld_ptr(G3_scratch, Lbyte_code, G3_scratch); // get entry addr - jmp( G3_scratch, 0 ); - if (bcp_incr != 0) delayed()->inc(Lbcp, bcp_incr); - else delayed()->nop(); -} - - -// Helpers for expression stack - -// Longs and doubles are Category 2 computational types in the -// JVM specification (section 3.11.1) and take 2 expression stack or -// local slots. -// Aligning them on 32 bit with tagged stacks is hard because the code generated -// for the dup* bytecodes depends on what types are already on the stack. -// If the types are split into the two stack/local slots, that is much easier -// (and we can use 0 for non-reference tags). - -// Known good alignment in _LP64 but unknown otherwise -void InterpreterMacroAssembler::load_unaligned_double(Register r1, int offset, FloatRegister d) { - assert_not_delayed(); - - ldf(FloatRegisterImpl::D, r1, offset, d); -} - -// Known good alignment in _LP64 but unknown otherwise -void InterpreterMacroAssembler::store_unaligned_double(FloatRegister d, Register r1, int offset) { - assert_not_delayed(); - - stf(FloatRegisterImpl::D, d, r1, offset); - // store something more useful here - debug_only(stx(G0, r1, offset+Interpreter::stackElementSize);) -} - - -// Known good alignment in _LP64 but unknown otherwise -void InterpreterMacroAssembler::load_unaligned_long(Register r1, int offset, Register rd) { - assert_not_delayed(); - ldx(r1, offset, rd); -} - -// Known good alignment in _LP64 but unknown otherwise -void InterpreterMacroAssembler::store_unaligned_long(Register l, Register r1, int offset) { - assert_not_delayed(); - - stx(l, r1, offset); - // store something more useful here - stx(G0, r1, offset+Interpreter::stackElementSize); -} - -void InterpreterMacroAssembler::pop_i(Register r) { - assert_not_delayed(); - ld(Lesp, Interpreter::expr_offset_in_bytes(0), r); - inc(Lesp, Interpreter::stackElementSize); - debug_only(verify_esp(Lesp)); -} - -void InterpreterMacroAssembler::pop_ptr(Register r, Register scratch) { - assert_not_delayed(); - ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), r); - inc(Lesp, Interpreter::stackElementSize); - debug_only(verify_esp(Lesp)); -} - -void InterpreterMacroAssembler::pop_l(Register r) { - assert_not_delayed(); - load_unaligned_long(Lesp, Interpreter::expr_offset_in_bytes(0), r); - inc(Lesp, 2*Interpreter::stackElementSize); - debug_only(verify_esp(Lesp)); -} - - -void InterpreterMacroAssembler::pop_f(FloatRegister f, Register scratch) { - assert_not_delayed(); - ldf(FloatRegisterImpl::S, Lesp, Interpreter::expr_offset_in_bytes(0), f); - inc(Lesp, Interpreter::stackElementSize); - debug_only(verify_esp(Lesp)); -} - - -void InterpreterMacroAssembler::pop_d(FloatRegister f, Register scratch) { - assert_not_delayed(); - load_unaligned_double(Lesp, Interpreter::expr_offset_in_bytes(0), f); - inc(Lesp, 2*Interpreter::stackElementSize); - debug_only(verify_esp(Lesp)); -} - - -void InterpreterMacroAssembler::push_i(Register r) { - assert_not_delayed(); - debug_only(verify_esp(Lesp)); - st(r, Lesp, 0); - dec(Lesp, Interpreter::stackElementSize); -} - -void InterpreterMacroAssembler::push_ptr(Register r) { - assert_not_delayed(); - st_ptr(r, Lesp, 0); - dec(Lesp, Interpreter::stackElementSize); -} - -// remember: our convention for longs in SPARC is: -// O0 (Otos_l1) has high-order part in first word, -// O1 (Otos_l2) has low-order part in second word - -void InterpreterMacroAssembler::push_l(Register r) { - assert_not_delayed(); - debug_only(verify_esp(Lesp)); - // Longs are stored in memory-correct order, even if unaligned. - int offset = -Interpreter::stackElementSize; - store_unaligned_long(r, Lesp, offset); - dec(Lesp, 2 * Interpreter::stackElementSize); -} - - -void InterpreterMacroAssembler::push_f(FloatRegister f) { - assert_not_delayed(); - debug_only(verify_esp(Lesp)); - stf(FloatRegisterImpl::S, f, Lesp, 0); - dec(Lesp, Interpreter::stackElementSize); -} - - -void InterpreterMacroAssembler::push_d(FloatRegister d) { - assert_not_delayed(); - debug_only(verify_esp(Lesp)); - // Longs are stored in memory-correct order, even if unaligned. - int offset = -Interpreter::stackElementSize; - store_unaligned_double(d, Lesp, offset); - dec(Lesp, 2 * Interpreter::stackElementSize); -} - - -void InterpreterMacroAssembler::push(TosState state) { - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); - switch (state) { - case atos: push_ptr(); break; - case btos: // fall through - case ztos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: push_i(); break; - case ltos: push_l(); break; - case ftos: push_f(); break; - case dtos: push_d(); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } -} - - -void InterpreterMacroAssembler::pop(TosState state) { - switch (state) { - case atos: pop_ptr(); break; - case btos: // fall through - case ztos: // fall through - case ctos: // fall through - case stos: // fall through - case itos: pop_i(); break; - case ltos: pop_l(); break; - case ftos: pop_f(); break; - case dtos: pop_d(); break; - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); -} - - -// Helpers for swap and dup -void InterpreterMacroAssembler::load_ptr(int n, Register val) { - ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(n), val); -} -void InterpreterMacroAssembler::store_ptr(int n, Register val) { - st_ptr(val, Lesp, Interpreter::expr_offset_in_bytes(n)); -} - - -void InterpreterMacroAssembler::load_receiver(Register param_count, - Register recv) { - sll(param_count, Interpreter::logStackElementSize, param_count); - ld_ptr(Lesp, param_count, recv); // gets receiver oop -} - -void InterpreterMacroAssembler::empty_expression_stack() { - // Reset Lesp. - sub( Lmonitors, wordSize, Lesp ); - - // Reset SP by subtracting more space from Lesp. - Label done; - assert(G4_scratch != Gframe_size, "Only you can prevent register aliasing!"); - - // A native does not need to do this, since its callee does not change SP. - ld(Lmethod, Method::access_flags_offset(), Gframe_size); // Load access flags. - btst(JVM_ACC_NATIVE, Gframe_size); - br(Assembler::notZero, false, Assembler::pt, done); - delayed()->nop(); - - // Compute max expression stack+register save area - ld_ptr(Lmethod, in_bytes(Method::const_offset()), Gframe_size); - lduh(Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size); // Load max stack. - add(Gframe_size, frame::memory_parameter_word_sp_offset+Method::extra_stack_entries(), Gframe_size ); - - // - // now set up a stack frame with the size computed above - // - //round_to( Gframe_size, WordsPerLong ); // -- moved down to the "and" below - sll( Gframe_size, LogBytesPerWord, Gframe_size ); - sub( Lesp, Gframe_size, Gframe_size ); - and3( Gframe_size, -(2 * wordSize), Gframe_size ); // align SP (downwards) to an 8/16-byte boundary - debug_only(verify_sp(Gframe_size, G4_scratch)); - sub(Gframe_size, STACK_BIAS, Gframe_size ); - mov(Gframe_size, SP); - - bind(done); -} - - -#ifdef ASSERT -void InterpreterMacroAssembler::verify_sp(Register Rsp, Register Rtemp) { - Label Bad, OK; - - // Saved SP must be aligned. - btst(2*BytesPerWord-1, Rsp); - br(Assembler::notZero, false, Assembler::pn, Bad); - delayed()->nop(); - - // Saved SP, plus register window size, must not be above FP. - add(Rsp, frame::register_save_words * wordSize, Rtemp); - sub(Rtemp, STACK_BIAS, Rtemp); // Bias Rtemp before cmp to FP - cmp_and_brx_short(Rtemp, FP, Assembler::greaterUnsigned, Assembler::pn, Bad); - - // Saved SP must not be ridiculously below current SP. - size_t maxstack = MAX2(JavaThread::stack_size_at_create(), (size_t) 4*K*K); - set(maxstack, Rtemp); - sub(SP, Rtemp, Rtemp); - add(Rtemp, STACK_BIAS, Rtemp); // Unbias Rtemp before cmp to Rsp - cmp_and_brx_short(Rsp, Rtemp, Assembler::lessUnsigned, Assembler::pn, Bad); - - ba_short(OK); - - bind(Bad); - stop("on return to interpreted call, restored SP is corrupted"); - - bind(OK); -} - - -void InterpreterMacroAssembler::verify_esp(Register Resp) { - // about to read or write Resp[0] - // make sure it is not in the monitors or the register save area - Label OK1, OK2; - - cmp(Resp, Lmonitors); - brx(Assembler::lessUnsigned, true, Assembler::pt, OK1); - delayed()->sub(Resp, frame::memory_parameter_word_sp_offset * wordSize, Resp); - stop("too many pops: Lesp points into monitor area"); - bind(OK1); - sub(Resp, STACK_BIAS, Resp); - cmp(Resp, SP); - brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, OK2); - delayed()->add(Resp, STACK_BIAS + frame::memory_parameter_word_sp_offset * wordSize, Resp); - stop("too many pushes: Lesp points into register window"); - bind(OK2); -} -#endif // ASSERT - -// Load compiled (i2c) or interpreter entry when calling from interpreted and -// do the call. Centralized so that all interpreter calls will do the same actions. -// If jvmti single stepping is on for a thread we must not call compiled code. -void InterpreterMacroAssembler::call_from_interpreter(Register target, Register scratch, Register Rret) { - - // Assume we want to go compiled if available - - ld_ptr(G5_method, in_bytes(Method::from_interpreted_offset()), target); - - if (JvmtiExport::can_post_interpreter_events()) { - // 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. - verify_thread(); - Label skip_compiled_code; - - const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); - ld(interp_only, scratch); - cmp_zero_and_br(Assembler::notZero, scratch, skip_compiled_code, true, Assembler::pn); - delayed()->ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target); - bind(skip_compiled_code); - } - - // the i2c_adapters need Method* in G5_method (right? %%%) - // do the call -#ifdef ASSERT - { - Label ok; - br_notnull_short(target, Assembler::pt, ok); - stop("null entry point"); - bind(ok); - } -#endif // ASSERT - - // Adjust Rret first so Llast_SP can be same as Rret - add(Rret, -frame::pc_return_offset, O7); - add(Lesp, BytesPerWord, Gargs); // setup parameter pointer - // Record SP so we can remove any stack space allocated by adapter transition - jmp(target, 0); - delayed()->mov(SP, Llast_SP); -} - -void InterpreterMacroAssembler::if_cmp(Condition cc, bool ptr_compare) { - assert_not_delayed(); - - Label not_taken; - if (ptr_compare) brx(cc, false, Assembler::pn, not_taken); - else br (cc, false, Assembler::pn, not_taken); - delayed()->nop(); - - TemplateTable::branch(false,false); - - bind(not_taken); - - profile_not_taken_branch(G3_scratch); -} - - -void InterpreterMacroAssembler::get_2_byte_integer_at_bcp( - int bcp_offset, - Register Rtmp, - Register Rdst, - signedOrNot is_signed, - setCCOrNot should_set_CC ) { - assert(Rtmp != Rdst, "need separate temp register"); - assert_not_delayed(); - switch (is_signed) { - default: ShouldNotReachHere(); - - case Signed: ldsb( Lbcp, bcp_offset, Rdst ); break; // high byte - case Unsigned: ldub( Lbcp, bcp_offset, Rdst ); break; // high byte - } - ldub( Lbcp, bcp_offset + 1, Rtmp ); // low byte - sll( Rdst, BitsPerByte, Rdst); - switch (should_set_CC ) { - default: ShouldNotReachHere(); - - case set_CC: orcc( Rdst, Rtmp, Rdst ); break; - case dont_set_CC: or3( Rdst, Rtmp, Rdst ); break; - } -} - - -void InterpreterMacroAssembler::get_4_byte_integer_at_bcp( - int bcp_offset, - Register Rtmp, - Register Rdst, - setCCOrNot should_set_CC ) { - assert(Rtmp != Rdst, "need separate temp register"); - assert_not_delayed(); - add( Lbcp, bcp_offset, Rtmp); - andcc( Rtmp, 3, G0); - Label aligned; - switch (should_set_CC ) { - default: ShouldNotReachHere(); - - case set_CC: break; - case dont_set_CC: break; - } - - br(Assembler::zero, true, Assembler::pn, aligned); - delayed()->ldsw(Rtmp, 0, Rdst); - - ldub(Lbcp, bcp_offset + 3, Rdst); - ldub(Lbcp, bcp_offset + 2, Rtmp); sll(Rtmp, 8, Rtmp); or3(Rtmp, Rdst, Rdst); - ldub(Lbcp, bcp_offset + 1, Rtmp); sll(Rtmp, 16, Rtmp); or3(Rtmp, Rdst, Rdst); - ldsb(Lbcp, bcp_offset + 0, Rtmp); sll(Rtmp, 24, Rtmp); - or3(Rtmp, Rdst, Rdst ); - - bind(aligned); - if (should_set_CC == set_CC) tst(Rdst); -} - -void InterpreterMacroAssembler::get_cache_index_at_bcp(Register temp, Register index, - int bcp_offset, size_t index_size) { - assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); - if (index_size == sizeof(u2)) { - get_2_byte_integer_at_bcp(bcp_offset, temp, index, Unsigned); - } else if (index_size == sizeof(u4)) { - get_4_byte_integer_at_bcp(bcp_offset, temp, index); - assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); - xor3(index, -1, index); // convert to plain index - } else if (index_size == sizeof(u1)) { - ldub(Lbcp, bcp_offset, index); - } else { - ShouldNotReachHere(); - } -} - - -void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, Register tmp, - int bcp_offset, size_t index_size) { - assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); - assert_different_registers(cache, tmp); - assert_not_delayed(); - get_cache_index_at_bcp(cache, tmp, bcp_offset, index_size); - // convert from field index to ConstantPoolCacheEntry index and from - // word index to byte offset - sll(tmp, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord), tmp); - add(LcpoolCache, tmp, cache); -} - - -void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, - Register temp, - Register bytecode, - int byte_no, - int bcp_offset, - size_t index_size) { - get_cache_and_index_at_bcp(cache, temp, bcp_offset, index_size); - ld_ptr(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset(), bytecode); - const int shift_count = (1 + byte_no) * BitsPerByte; - assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) || - (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift), - "correct shift count"); - srl(bytecode, shift_count, bytecode); - assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); - and3(bytecode, ConstantPoolCacheEntry::bytecode_1_mask, bytecode); -} - - -void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, Register tmp, - int bcp_offset, size_t index_size) { - assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); - assert_different_registers(cache, tmp); - assert_not_delayed(); - if (index_size == sizeof(u2)) { - get_2_byte_integer_at_bcp(bcp_offset, cache, tmp, Unsigned); - } else { - ShouldNotReachHere(); // other sizes not supported here - } - // convert from field index to ConstantPoolCacheEntry index - // and from word index to byte offset - sll(tmp, exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord), tmp); - // skip past the header - add(tmp, in_bytes(ConstantPoolCache::base_offset()), tmp); - // construct pointer to cache entry - add(LcpoolCache, tmp, cache); -} - - -// Load object from cpool->resolved_references(index) -void InterpreterMacroAssembler::load_resolved_reference_at_index( - Register result, Register index, Register tmp) { - assert_different_registers(result, index, tmp); - assert_not_delayed(); - // convert from field index to resolved_references() index and from - // word index to byte offset. Since this is a java object, it can be compressed - sll(index, LogBytesPerHeapOop, index); - get_constant_pool(result); - // load pointer for resolved_references[] objArray - ld_ptr(result, ConstantPool::cache_offset_in_bytes(), result); - ld_ptr(result, ConstantPoolCache::resolved_references_offset_in_bytes(), result); - resolve_oop_handle(result, tmp); - // Add in the index - add(result, index, result); - load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, tmp); - // The resulting oop is null if the reference is not yet resolved. - // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy. -} - - -// load cpool->resolved_klass_at(index) -void InterpreterMacroAssembler::load_resolved_klass_at_offset(Register Rcpool, - Register Roffset, Register Rklass) { - // int value = *this_cp->int_at_addr(which); - // int resolved_klass_index = extract_low_short_from_int(value); - // - // Because SPARC is big-endian, the low_short is at (cpool->int_at_addr(which) + 2 bytes) - add(Roffset, Rcpool, Roffset); - lduh(Roffset, sizeof(ConstantPool) + 2, Roffset); // Roffset = resolved_klass_index - - Register Rresolved_klasses = Rklass; - ld_ptr(Rcpool, ConstantPool::resolved_klasses_offset_in_bytes(), Rresolved_klasses); - sll(Roffset, LogBytesPerWord, Roffset); - add(Roffset, Array::base_offset_in_bytes(), Roffset); - ld_ptr(Rresolved_klasses, Roffset, Rklass); -} - - -// Generate a subtype check: branch to ok_is_subtype if sub_klass is -// a subtype of super_klass. Blows registers Rsuper_klass, Rsub_klass, tmp1, tmp2. -void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, - Register Rsuper_klass, - Register Rtmp1, - Register Rtmp2, - Register Rtmp3, - Label &ok_is_subtype ) { - Label not_subtype; - - // Profile the not-null value's klass. - profile_typecheck(Rsub_klass, Rtmp1); - - check_klass_subtype_fast_path(Rsub_klass, Rsuper_klass, - Rtmp1, Rtmp2, - &ok_is_subtype, ¬_subtype, NULL); - - check_klass_subtype_slow_path(Rsub_klass, Rsuper_klass, - Rtmp1, Rtmp2, Rtmp3, /*hack:*/ noreg, - &ok_is_subtype, NULL); - - bind(not_subtype); - profile_typecheck_failed(Rtmp1); -} - -// Separate these two to allow for delay slot in middle -// These are used to do a test and full jump to exception-throwing code. - -// %%%%% Could possibly reoptimize this by testing to see if could use -// a single conditional branch (i.e. if span is small enough. -// If you go that route, than get rid of the split and give up -// on the delay-slot hack. - -void InterpreterMacroAssembler::throw_if_not_1_icc( Condition ok_condition, - Label& ok ) { - assert_not_delayed(); - br(ok_condition, true, pt, ok); - // DELAY SLOT -} - -void InterpreterMacroAssembler::throw_if_not_1_xcc( Condition ok_condition, - Label& ok ) { - assert_not_delayed(); - bp( ok_condition, true, Assembler::xcc, pt, ok); - // DELAY SLOT -} - -void InterpreterMacroAssembler::throw_if_not_1_x( Condition ok_condition, - Label& ok ) { - assert_not_delayed(); - brx(ok_condition, true, pt, ok); - // DELAY SLOT -} - -void InterpreterMacroAssembler::throw_if_not_2( address throw_entry_point, - Register Rscratch, - Label& ok ) { - assert(throw_entry_point != NULL, "entry point must be generated by now"); - AddressLiteral dest(throw_entry_point); - jump_to(dest, Rscratch); - delayed()->nop(); - bind(ok); -} - - -// And if you cannot use the delay slot, here is a shorthand: - -void InterpreterMacroAssembler::throw_if_not_icc( Condition ok_condition, - address throw_entry_point, - Register Rscratch ) { - Label ok; - if (ok_condition != never) { - throw_if_not_1_icc( ok_condition, ok); - delayed()->nop(); - } - throw_if_not_2( throw_entry_point, Rscratch, ok); -} -void InterpreterMacroAssembler::throw_if_not_xcc( Condition ok_condition, - address throw_entry_point, - Register Rscratch ) { - Label ok; - if (ok_condition != never) { - throw_if_not_1_xcc( ok_condition, ok); - delayed()->nop(); - } - throw_if_not_2( throw_entry_point, Rscratch, ok); -} -void InterpreterMacroAssembler::throw_if_not_x( Condition ok_condition, - address throw_entry_point, - Register Rscratch ) { - Label ok; - if (ok_condition != never) { - throw_if_not_1_x( ok_condition, ok); - delayed()->nop(); - } - throw_if_not_2( throw_entry_point, Rscratch, ok); -} - -// Check that index is in range for array, then shift index by index_shift, and put arrayOop + shifted_index into res -// Note: res is still shy of address by array offset into object. - -void InterpreterMacroAssembler::index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res) { - assert_not_delayed(); - - verify_oop(array); - // Sign extend since tos (index) can be a 32bit value. - sra(index, G0, index); - - // Check array. - Label ptr_ok; - tst(array); - throw_if_not_1_x(notZero, ptr_ok); - delayed()->ld(array, arrayOopDesc::length_offset_in_bytes(), tmp); // Check index. - throw_if_not_2(Interpreter::_throw_NullPointerException_entry, G3_scratch, ptr_ok); - - Label index_ok; - cmp(index, tmp); - throw_if_not_1_icc(lessUnsigned, index_ok); - if (index_shift > 0) { - delayed()->sll(index, index_shift, index); - } else { - delayed()->add(array, index, res); // addr - const offset in index - } - // Pass the array to create more detailed exceptions. - // Convention: move aberrant index into Otos_i for exception message. - mov(index, Otos_i); - mov(array, G3_scratch); - throw_if_not_2(Interpreter::_throw_ArrayIndexOutOfBoundsException_entry, G4_scratch, index_ok); - - // add offset if didn't do it in delay slot - if (index_shift > 0) { add(array, index, res); } // addr - const offset in index -} - - -void InterpreterMacroAssembler::index_check(Register array, Register index, int index_shift, Register tmp, Register res) { - assert_not_delayed(); - - // pop array - pop_ptr(array); - - // check array - index_check_without_pop(array, index, index_shift, tmp, res); -} - - -void InterpreterMacroAssembler::get_const(Register Rdst) { - ld_ptr(Lmethod, in_bytes(Method::const_offset()), Rdst); -} - - -void InterpreterMacroAssembler::get_constant_pool(Register Rdst) { - get_const(Rdst); - ld_ptr(Rdst, in_bytes(ConstMethod::constants_offset()), Rdst); -} - - -void InterpreterMacroAssembler::get_constant_pool_cache(Register Rdst) { - get_constant_pool(Rdst); - ld_ptr(Rdst, ConstantPool::cache_offset_in_bytes(), Rdst); -} - - -void InterpreterMacroAssembler::get_cpool_and_tags(Register Rcpool, Register Rtags) { - get_constant_pool(Rcpool); - ld_ptr(Rcpool, ConstantPool::tags_offset_in_bytes(), Rtags); -} - - -// unlock if synchronized method -// -// Unlock the receiver if this is a synchronized method. -// Unlock any Java monitors from syncronized blocks. -// -// If there are locked Java monitors -// If throw_monitor_exception -// throws IllegalMonitorStateException -// Else if install_monitor_exception -// installs IllegalMonitorStateException -// Else -// no error processing -void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, - bool throw_monitor_exception, - bool install_monitor_exception) { - Label unlocked, unlock, no_unlock; - - // get the value of _do_not_unlock_if_synchronized into G1_scratch - const Address do_not_unlock_if_synchronized(G2_thread, - JavaThread::do_not_unlock_if_synchronized_offset()); - ldbool(do_not_unlock_if_synchronized, G1_scratch); - stbool(G0, do_not_unlock_if_synchronized); // reset the flag - - // check if synchronized method - const Address access_flags(Lmethod, Method::access_flags_offset()); - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); - push(state); // save tos - ld(access_flags, G3_scratch); // Load access flags. - btst(JVM_ACC_SYNCHRONIZED, G3_scratch); - br(zero, false, pt, unlocked); - delayed()->nop(); - - // Don't unlock anything if the _do_not_unlock_if_synchronized flag - // is set. - cmp_zero_and_br(Assembler::notZero, G1_scratch, no_unlock); - delayed()->nop(); - - // BasicObjectLock will be first in list, since this is a synchronized method. However, need - // to check that the object has not been unlocked by an explicit monitorexit bytecode. - - //Intel: if (throw_monitor_exception) ... else ... - // Entry already unlocked, need to throw exception - //... - - // pass top-most monitor elem - add( top_most_monitor(), O1 ); - - ld_ptr(O1, BasicObjectLock::obj_offset_in_bytes(), G3_scratch); - br_notnull_short(G3_scratch, pt, unlock); - - if (throw_monitor_exception) { - // Entry already unlocked need to throw an exception - MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); - should_not_reach_here(); - } else { - // Monitor already unlocked during a stack unroll. - // If requested, install an illegal_monitor_state_exception. - // Continue with stack unrolling. - if (install_monitor_exception) { - MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); - } - ba_short(unlocked); - } - - bind(unlock); - - unlock_object(O1); - - bind(unlocked); - - // I0, I1: Might contain return value - - // Check that all monitors are unlocked - { Label loop, exception, entry, restart; - - Register Rmptr = O0; - Register Rtemp = O1; - Register Rlimit = Lmonitors; - const jint delta = frame::interpreter_frame_monitor_size() * wordSize; - assert( (delta & LongAlignmentMask) == 0, - "sizeof BasicObjectLock must be even number of doublewords"); - - #ifdef ASSERT - add(top_most_monitor(), Rmptr, delta); - { Label L; - // ensure that Rmptr starts out above (or at) Rlimit - cmp_and_brx_short(Rmptr, Rlimit, Assembler::greaterEqualUnsigned, pn, L); - stop("monitor stack has negative size"); - bind(L); - } - #endif - bind(restart); - ba(entry); - delayed()-> - add(top_most_monitor(), Rmptr, delta); // points to current entry, starting with bottom-most entry - - // Entry is still locked, need to throw exception - bind(exception); - if (throw_monitor_exception) { - MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); - should_not_reach_here(); - } else { - // Stack unrolling. Unlock object and if requested, install illegal_monitor_exception. - // Unlock does not block, so don't have to worry about the frame - unlock_object(Rmptr); - if (install_monitor_exception) { - MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::new_illegal_monitor_state_exception)); - } - ba_short(restart); - } - - bind(loop); - cmp(Rtemp, G0); // check if current entry is used - brx(Assembler::notEqual, false, pn, exception); - delayed()-> - dec(Rmptr, delta); // otherwise advance to next entry - #ifdef ASSERT - { Label L; - // ensure that Rmptr has not somehow stepped below Rlimit - cmp_and_brx_short(Rmptr, Rlimit, Assembler::greaterEqualUnsigned, pn, L); - stop("ran off the end of the monitor stack"); - bind(L); - } - #endif - bind(entry); - cmp(Rmptr, Rlimit); // check if bottom reached - brx(Assembler::notEqual, true, pn, loop); // if not at bottom then check this entry - delayed()-> - ld_ptr(Rmptr, BasicObjectLock::obj_offset_in_bytes() - delta, Rtemp); - } - - bind(no_unlock); - pop(state); - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); -} - -void InterpreterMacroAssembler::narrow(Register result) { - - ld_ptr(Address(Lmethod, Method::const_offset()), G3_scratch); - ldub(G3_scratch, in_bytes(ConstMethod::result_type_offset()), G3_scratch); - - Label notBool, notByte, notChar, done; - - // common case first - cmp(G3_scratch, T_INT); - br(Assembler::equal, true, pn, done); - delayed()->nop(); - - cmp(G3_scratch, T_BOOLEAN); - br(Assembler::notEqual, true, pn, notBool); - delayed()->cmp(G3_scratch, T_BYTE); - and3(result, 1, result); - ba(done); - delayed()->nop(); - - bind(notBool); - // cmp(G3_scratch, T_BYTE); - br(Assembler::notEqual, true, pn, notByte); - delayed()->cmp(G3_scratch, T_CHAR); - sll(result, 24, result); - sra(result, 24, result); - ba(done); - delayed()->nop(); - - bind(notByte); - // cmp(G3_scratch, T_CHAR); - sll(result, 16, result); - br(Assembler::notEqual, true, pn, done); - delayed()->sra(result, 16, result); - // sll(result, 16, result); - srl(result, 16, result); - - // bind(notChar); - // must be short, instructions already executed in delay slot - // sll(result, 16, result); - // sra(result, 16, result); - - bind(done); -} - -// remove activation -// -// Unlock the receiver if this is a synchronized method. -// Unlock any Java monitors from syncronized blocks. -// Remove the activation from the stack. -// -// If there are locked Java monitors -// If throw_monitor_exception -// throws IllegalMonitorStateException -// Else if install_monitor_exception -// installs IllegalMonitorStateException -// Else -// no error processing -void InterpreterMacroAssembler::remove_activation(TosState state, - bool throw_monitor_exception, - bool install_monitor_exception) { - - unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); - - // save result (push state before jvmti call and pop it afterwards) and notify jvmti - notify_method_exit(false, state, NotifyJVMTI); - - if (StackReservedPages > 0) { - // testing if Stack Reserved Area needs to be re-enabled - Label no_reserved_zone_enabling; - ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G3_scratch); - cmp_and_brx_short(SP, G3_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling); - - call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError), G2_thread); - should_not_reach_here(); - - bind(no_reserved_zone_enabling); - } - - interp_verify_oop(Otos_i, state, __FILE__, __LINE__); - verify_thread(); - - // return tos - assert(Otos_l1 == Otos_i, "adjust code below"); - switch (state) { - case ltos: mov(Otos_l, Otos_l->after_save()); break; // O0 -> I0 - case btos: // fall through - case ztos: // fall through - case ctos: - case stos: // fall through - case atos: // fall through - case itos: mov(Otos_l1, Otos_l1->after_save()); break; // O0 -> I0 - case ftos: // fall through - case dtos: // fall through - case vtos: /* nothing to do */ break; - default : ShouldNotReachHere(); - } -} - -// Lock object -// -// Argument - lock_reg points to the BasicObjectLock to be used for locking, -// it must be initialized with the object to lock -void InterpreterMacroAssembler::lock_object(Register lock_reg, Register Object) { - if (UseHeavyMonitors) { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg); - } - else { - Register obj_reg = Object; - Register mark_reg = G4_scratch; - Register temp_reg = G1_scratch; - Address lock_addr(lock_reg, BasicObjectLock::lock_offset_in_bytes()); - Address mark_addr(obj_reg, oopDesc::mark_offset_in_bytes()); - Label done; - - Label slow_case; - - assert_different_registers(lock_reg, obj_reg, mark_reg, temp_reg); - - // load markWord from object into mark_reg - ld_ptr(mark_addr, mark_reg); - - if (UseBiasedLocking) { - biased_locking_enter(obj_reg, mark_reg, temp_reg, done, &slow_case); - } - - // get the address of basicLock on stack that will be stored in the object - // we need a temporary register here as we do not want to clobber lock_reg - // (cas clobbers the destination register) - mov(lock_reg, temp_reg); - // set mark reg to be (markWord of object | UNLOCK_VALUE) - or3(mark_reg, markWord::unlocked_value, mark_reg); - // initialize the box (Must happen before we update the object mark!) - st_ptr(mark_reg, lock_addr, BasicLock::displaced_header_offset_in_bytes()); - // compare and exchange object_addr, markWord | 1, stack address of basicLock - assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - cas_ptr(mark_addr.base(), mark_reg, temp_reg); - - // if the compare and exchange succeeded we are done (we saw an unlocked object) - cmp_and_brx_short(mark_reg, temp_reg, Assembler::equal, Assembler::pt, done); - - // We did not see an unlocked object so try the fast recursive case - - // Check if owner is self by comparing the value in the markWord of object - // with the stack pointer - sub(temp_reg, SP, temp_reg); - sub(temp_reg, STACK_BIAS, temp_reg); - assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - - // Composite "andcc" test: - // (a) %sp -vs- markword proximity check, and, - // (b) verify mark word LSBs == 0 (Stack-locked). - // - // FFFFF003/FFFFFFFFFFFF003 is (markWord::lock_mask_in_place | -os::vm_page_size()) - // Note that the page size used for %sp proximity testing is arbitrary and is - // unrelated to the actual MMU page size. We use a 'logical' page size of - // 4096 bytes. F..FFF003 is designed to fit conveniently in the SIMM13 immediate - // field of the andcc instruction. - andcc (temp_reg, 0xFFFFF003, G0) ; - - // if condition is true we are done and hence we can store 0 in the displaced - // header indicating it is a recursive lock and be done - brx(Assembler::zero, true, Assembler::pt, done); - delayed()->st_ptr(G0, lock_addr, BasicLock::displaced_header_offset_in_bytes()); - - // none of the above fast optimizations worked so we have to get into the - // slow case of monitor enter - bind(slow_case); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg); - - bind(done); - } -} - -// Unlocks an object. Used in monitorexit bytecode and remove_activation. -// -// Argument - lock_reg points to the BasicObjectLock for lock -// Throw IllegalMonitorException if object is not locked by current thread -void InterpreterMacroAssembler::unlock_object(Register lock_reg) { - if (UseHeavyMonitors) { - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - } else { - Register obj_reg = G3_scratch; - Register mark_reg = G4_scratch; - Register displaced_header_reg = G1_scratch; - Address lockobj_addr(lock_reg, BasicObjectLock::obj_offset_in_bytes()); - Address mark_addr(obj_reg, oopDesc::mark_offset_in_bytes()); - Label done; - - if (UseBiasedLocking) { - // load the object out of the BasicObjectLock - ld_ptr(lockobj_addr, obj_reg); - biased_locking_exit(mark_addr, mark_reg, done, true); - st_ptr(G0, lockobj_addr); // free entry - } - - // Test first if we are in the fast recursive case - Address lock_addr(lock_reg, BasicObjectLock::lock_offset_in_bytes() + BasicLock::displaced_header_offset_in_bytes()); - ld_ptr(lock_addr, displaced_header_reg); - br_null(displaced_header_reg, true, Assembler::pn, done); - delayed()->st_ptr(G0, lockobj_addr); // free entry - - // See if it is still a light weight lock, if so we just unlock - // the object and we are done - - if (!UseBiasedLocking) { - // load the object out of the BasicObjectLock - ld_ptr(lockobj_addr, obj_reg); - } - - // we have the displaced header in displaced_header_reg - // we expect to see the stack address of the basicLock in case the - // lock is still a light weight lock (lock_reg) - assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - cas_ptr(mark_addr.base(), lock_reg, displaced_header_reg); - cmp(lock_reg, displaced_header_reg); - brx(Assembler::equal, true, Assembler::pn, done); - delayed()->st_ptr(G0, lockobj_addr); // free entry - - // The lock has been converted into a heavy lock and hence - // we need to get into the slow case - - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); - - bind(done); - } -} - -// Get the method data pointer from the Method* and set the -// specified register to its value. - -void InterpreterMacroAssembler::set_method_data_pointer() { - assert(ProfileInterpreter, "must be profiling interpreter"); - Label get_continue; - - ld_ptr(Lmethod, in_bytes(Method::method_data_offset()), ImethodDataPtr); - test_method_data_pointer(get_continue); - add(ImethodDataPtr, in_bytes(MethodData::data_offset()), ImethodDataPtr); - bind(get_continue); -} - -// Set the method data pointer for the current bcp. - -void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { - assert(ProfileInterpreter, "must be profiling interpreter"); - Label zero_continue; - - // Test MDO to avoid the call if it is NULL. - ld_ptr(Lmethod, in_bytes(Method::method_data_offset()), ImethodDataPtr); - test_method_data_pointer(zero_continue); - call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), Lmethod, Lbcp); - add(ImethodDataPtr, in_bytes(MethodData::data_offset()), ImethodDataPtr); - add(ImethodDataPtr, O0, ImethodDataPtr); - bind(zero_continue); -} - -// Test ImethodDataPtr. If it is null, continue at the specified label - -void InterpreterMacroAssembler::test_method_data_pointer(Label& zero_continue) { - assert(ProfileInterpreter, "must be profiling interpreter"); - br_null_short(ImethodDataPtr, Assembler::pn, zero_continue); -} - -void InterpreterMacroAssembler::verify_method_data_pointer() { - assert(ProfileInterpreter, "must be profiling interpreter"); -#ifdef ASSERT - Label verify_continue; - test_method_data_pointer(verify_continue); - - // If the mdp is valid, it will point to a DataLayout header which is - // consistent with the bcp. The converse is highly probable also. - lduh(ImethodDataPtr, in_bytes(DataLayout::bci_offset()), G3_scratch); - ld_ptr(Lmethod, Method::const_offset(), O5); - add(G3_scratch, in_bytes(ConstMethod::codes_offset()), G3_scratch); - add(G3_scratch, O5, G3_scratch); - cmp(Lbcp, G3_scratch); - brx(Assembler::equal, false, Assembler::pt, verify_continue); - - Register temp_reg = O5; - delayed()->mov(ImethodDataPtr, temp_reg); - // %%% should use call_VM_leaf here? - //call_VM_leaf(noreg, ..., Lmethod, Lbcp, ImethodDataPtr); - save_frame_and_mov(sizeof(jdouble) / wordSize, Lmethod, O0, Lbcp, O1); - Address d_save(FP, -sizeof(jdouble) + STACK_BIAS); - stf(FloatRegisterImpl::D, Ftos_d, d_save); - mov(temp_reg->after_save(), O2); - save_thread(L7_thread_cache); - call(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), relocInfo::none); - delayed()->nop(); - restore_thread(L7_thread_cache); - ldf(FloatRegisterImpl::D, d_save, Ftos_d); - restore(); - bind(verify_continue); -#endif // ASSERT -} - -void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, - Register method_counters, - Register Rtmp, - Label &profile_continue) { - assert(ProfileInterpreter, "must be profiling interpreter"); - // Control will flow to "profile_continue" if the counter is less than the - // limit or if we call profile_method() - - Label done; - - // if no method data exists, and the counter is high enough, make one - br_notnull_short(ImethodDataPtr, Assembler::pn, done); - - // Test to see if we should create a method data oop - Address profile_limit(method_counters, MethodCounters::interpreter_profile_limit_offset()); - ld(profile_limit, Rtmp); - cmp(invocation_count, Rtmp); - // Use long branches because call_VM() code and following code generated by - // test_backedge_count_for_osr() is large in debug VM. - br(Assembler::lessUnsigned, false, Assembler::pn, profile_continue); - delayed()->nop(); - - // Build it now. - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); - set_method_data_pointer_for_bcp(); - ba(profile_continue); - delayed()->nop(); - bind(done); -} - -// Store a value at some constant offset from the method data pointer. - -void InterpreterMacroAssembler::set_mdp_data_at(int constant, Register value) { - assert(ProfileInterpreter, "must be profiling interpreter"); - st_ptr(value, ImethodDataPtr, constant); -} - -void InterpreterMacroAssembler::increment_mdp_data_at(Address counter, - Register bumped_count, - bool decrement) { - assert(ProfileInterpreter, "must be profiling interpreter"); - - // Load the counter. - ld_ptr(counter, bumped_count); - - if (decrement) { - // Decrement the register. Set condition codes. - subcc(bumped_count, DataLayout::counter_increment, bumped_count); - - // If the decrement causes the counter to overflow, stay negative - Label L; - brx(Assembler::negative, true, Assembler::pn, L); - - // Store the decremented counter, if it is still negative. - delayed()->st_ptr(bumped_count, counter); - bind(L); - } else { - // Increment the register. Set carry flag. - addcc(bumped_count, DataLayout::counter_increment, bumped_count); - - // If the increment causes the counter to overflow, pull back by 1. - assert(DataLayout::counter_increment == 1, "subc works"); - subc(bumped_count, G0, bumped_count); - - // Store the incremented counter. - st_ptr(bumped_count, counter); - } -} - -// Increment the value at some constant offset from the method data pointer. - -void InterpreterMacroAssembler::increment_mdp_data_at(int constant, - Register bumped_count, - bool decrement) { - // Locate the counter at a fixed offset from the mdp: - Address counter(ImethodDataPtr, constant); - increment_mdp_data_at(counter, bumped_count, decrement); -} - -// Increment the value at some non-fixed (reg + constant) offset from -// the method data pointer. - -void InterpreterMacroAssembler::increment_mdp_data_at(Register reg, - int constant, - Register bumped_count, - Register scratch2, - bool decrement) { - // Add the constant to reg to get the offset. - add(ImethodDataPtr, reg, scratch2); - Address counter(scratch2, constant); - increment_mdp_data_at(counter, bumped_count, decrement); -} - -// Set a flag value at the current method data pointer position. -// Updates a single byte of the header, to avoid races with other header bits. - -void InterpreterMacroAssembler::set_mdp_flag_at(int flag_constant, - Register scratch) { - assert(ProfileInterpreter, "must be profiling interpreter"); - // Load the data header - ldub(ImethodDataPtr, in_bytes(DataLayout::flags_offset()), scratch); - - // Set the flag - or3(scratch, flag_constant, scratch); - - // Store the modified header. - stb(scratch, ImethodDataPtr, in_bytes(DataLayout::flags_offset())); -} - -// Test the location at some offset from the method data pointer. -// If it is not equal to value, branch to the not_equal_continue Label. -// Set condition codes to match the nullness of the loaded value. - -void InterpreterMacroAssembler::test_mdp_data_at(int offset, - Register value, - Label& not_equal_continue, - Register scratch) { - assert(ProfileInterpreter, "must be profiling interpreter"); - ld_ptr(ImethodDataPtr, offset, scratch); - cmp(value, scratch); - brx(Assembler::notEqual, false, Assembler::pn, not_equal_continue); - delayed()->tst(scratch); -} - -// Update the method data pointer by the displacement located at some fixed -// offset from the method data pointer. - -void InterpreterMacroAssembler::update_mdp_by_offset(int offset_of_disp, - Register scratch) { - assert(ProfileInterpreter, "must be profiling interpreter"); - ld_ptr(ImethodDataPtr, offset_of_disp, scratch); - add(ImethodDataPtr, scratch, ImethodDataPtr); -} - -// Update the method data pointer by the displacement located at the -// offset (reg + offset_of_disp). - -void InterpreterMacroAssembler::update_mdp_by_offset(Register reg, - int offset_of_disp, - Register scratch) { - assert(ProfileInterpreter, "must be profiling interpreter"); - add(reg, offset_of_disp, scratch); - ld_ptr(ImethodDataPtr, scratch, scratch); - add(ImethodDataPtr, scratch, ImethodDataPtr); -} - -// Update the method data pointer by a simple constant displacement. - -void InterpreterMacroAssembler::update_mdp_by_constant(int constant) { - assert(ProfileInterpreter, "must be profiling interpreter"); - add(ImethodDataPtr, constant, ImethodDataPtr); -} - -// Update the method data pointer for a _ret bytecode whose target -// was not among our cached targets. - -void InterpreterMacroAssembler::update_mdp_for_ret(TosState state, - Register return_bci) { - assert(ProfileInterpreter, "must be profiling interpreter"); - push(state); - st_ptr(return_bci, l_tmp); // protect return_bci, in case it is volatile - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), return_bci); - ld_ptr(l_tmp, return_bci); - pop(state); -} - -// Count a taken branch in the bytecodes. - -void InterpreterMacroAssembler::profile_taken_branch(Register scratch, Register bumped_count) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // We are taking a branch. Increment the taken count. - increment_mdp_data_at(in_bytes(JumpData::taken_offset()), bumped_count); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_offset(in_bytes(JumpData::displacement_offset()), scratch); - bind (profile_continue); - } -} - - -// Count a not-taken branch in the bytecodes. - -void InterpreterMacroAssembler::profile_not_taken_branch(Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // We are taking a branch. Increment the not taken count. - increment_mdp_data_at(in_bytes(BranchData::not_taken_offset()), scratch); - - // The method data pointer needs to be updated to correspond to the - // next bytecode. - update_mdp_by_constant(in_bytes(BranchData::branch_data_size())); - bind (profile_continue); - } -} - - -// Count a non-virtual call in the bytecodes. - -void InterpreterMacroAssembler::profile_call(Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // We are making a call. Increment the count. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(in_bytes(CounterData::counter_data_size())); - bind (profile_continue); - } -} - - -// Count a final call in the bytecodes. - -void InterpreterMacroAssembler::profile_final_call(Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // We are making a call. Increment the count. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); - bind (profile_continue); - } -} - - -// Count a virtual call in the bytecodes. - -void InterpreterMacroAssembler::profile_virtual_call(Register receiver, - Register scratch, - bool receiver_can_be_null) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - - Label skip_receiver_profile; - if (receiver_can_be_null) { - Label not_null; - br_notnull_short(receiver, Assembler::pt, not_null); - // We are making a call. Increment the count for null receiver. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); - ba_short(skip_receiver_profile); - bind(not_null); - } - - // Record the receiver type. - record_klass_in_profile(receiver, scratch, true); - bind(skip_receiver_profile); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size())); - bind(profile_continue); - } -} - -void InterpreterMacroAssembler::record_klass_in_profile_helper(Register receiver, Register scratch, - Label& done, bool is_virtual_call) { - if (TypeProfileWidth == 0) { - if (is_virtual_call) { - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); - } -#if INCLUDE_JVMCI - else if (EnableJVMCI) { - increment_mdp_data_at(in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()), scratch); - } -#endif - } else { - int non_profiled_offset = -1; - if (is_virtual_call) { - non_profiled_offset = in_bytes(CounterData::count_offset()); - } -#if INCLUDE_JVMCI - else if (EnableJVMCI) { - non_profiled_offset = in_bytes(ReceiverTypeData::nonprofiled_receiver_count_offset()); - } -#endif - - record_item_in_profile_helper(receiver, scratch, 0, done, TypeProfileWidth, - &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); - } -} - -void InterpreterMacroAssembler::record_item_in_profile_helper(Register item, - Register scratch, int start_row, Label& done, int total_rows, - OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, - int non_profiled_offset) { - int last_row = total_rows - 1; - assert(start_row <= last_row, "must be work left to do"); - // Test this row for both the item and for null. - // Take any of three different outcomes: - // 1. found item => increment count and goto done - // 2. found null => keep looking for case 1, maybe allocate this cell - // 3. found something else => keep looking for cases 1 and 2 - // Case 3 is handled by a recursive call. - for (int row = start_row; row <= last_row; row++) { - Label next_test; - bool test_for_null_also = (row == start_row); - - // See if the item is item[n]. - int item_offset = in_bytes(item_offset_fn(row)); - test_mdp_data_at(item_offset, item, next_test, scratch); - // delayed()->tst(scratch); - - // The receiver is item[n]. Increment count[n]. - int count_offset = in_bytes(item_count_offset_fn(row)); - increment_mdp_data_at(count_offset, scratch); - ba_short(done); - bind(next_test); - - if (test_for_null_also) { - Label found_null; - // Failed the equality check on item[n]... Test for null. - if (start_row == last_row) { - // The only thing left to do is handle the null case. - if (non_profiled_offset >= 0) { - brx(Assembler::zero, false, Assembler::pn, found_null); - delayed()->nop(); - // Item did not match any saved item and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - increment_mdp_data_at(non_profiled_offset, scratch); - ba_short(done); - bind(found_null); - } else { - brx(Assembler::notZero, false, Assembler::pt, done); - delayed()->nop(); - } - break; - } - // Since null is rare, make it be the branch-taken case. - brx(Assembler::zero, false, Assembler::pn, found_null); - delayed()->nop(); - - // Put all the "Case 3" tests here. - record_item_in_profile_helper(item, scratch, start_row + 1, done, total_rows, - item_offset_fn, item_count_offset_fn, non_profiled_offset); - - // Found a null. Keep searching for a matching item, - // but remember that this is an empty (unused) slot. - bind(found_null); - } - } - - // In the fall-through case, we found no matching item, but we - // observed the item[start_row] is NULL. - - // Fill in the item field and increment the count. - int item_offset = in_bytes(item_offset_fn(start_row)); - set_mdp_data_at(item_offset, item); - int count_offset = in_bytes(item_count_offset_fn(start_row)); - mov(DataLayout::counter_increment, scratch); - set_mdp_data_at(count_offset, scratch); - if (start_row > 0) { - ba_short(done); - } -} - -void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, - Register scratch, bool is_virtual_call) { - assert(ProfileInterpreter, "must be profiling"); - Label done; - - record_klass_in_profile_helper(receiver, scratch, done, is_virtual_call); - - bind (done); -} - - -// Count a ret in the bytecodes. - -void InterpreterMacroAssembler::profile_ret(TosState state, - Register return_bci, - Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - uint row; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // Update the total ret count. - increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch); - - for (row = 0; row < RetData::row_limit(); row++) { - Label next_test; - - // See if return_bci is equal to bci[n]: - test_mdp_data_at(in_bytes(RetData::bci_offset(row)), - return_bci, next_test, scratch); - - // return_bci is equal to bci[n]. Increment the count. - increment_mdp_data_at(in_bytes(RetData::bci_count_offset(row)), scratch); - - // The method data pointer needs to be updated to reflect the new target. - update_mdp_by_offset(in_bytes(RetData::bci_displacement_offset(row)), scratch); - ba_short(profile_continue); - bind(next_test); - } - - update_mdp_for_ret(state, return_bci); - - bind (profile_continue); - } -} - -// Profile an unexpected null in the bytecodes. -void InterpreterMacroAssembler::profile_null_seen(Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - set_mdp_flag_at(BitData::null_seen_byte_constant(), scratch); - - // The method data pointer needs to be updated. - int mdp_delta = in_bytes(BitData::bit_data_size()); - if (TypeProfileCasts) { - mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); - } - update_mdp_by_constant(mdp_delta); - - bind (profile_continue); - } -} - -void InterpreterMacroAssembler::profile_typecheck(Register klass, - Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - int mdp_delta = in_bytes(BitData::bit_data_size()); - if (TypeProfileCasts) { - mdp_delta = in_bytes(ReceiverTypeData::receiver_type_data_size()); - - // Record the object type. - record_klass_in_profile(klass, scratch, false); - } - - // The method data pointer needs to be updated. - update_mdp_by_constant(mdp_delta); - - bind (profile_continue); - } -} - -void InterpreterMacroAssembler::profile_typecheck_failed(Register scratch) { - if (ProfileInterpreter && TypeProfileCasts) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - int count_offset = in_bytes(CounterData::count_offset()); - // Back up the address, since we have already bumped the mdp. - count_offset -= in_bytes(ReceiverTypeData::receiver_type_data_size()); - - // *Decrement* the counter. We expect to see zero or small negatives. - increment_mdp_data_at(count_offset, scratch, true); - - bind (profile_continue); - } -} - -// Count the default case of a switch construct. - -void InterpreterMacroAssembler::profile_switch_default(Register scratch) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // Update the default case count - increment_mdp_data_at(in_bytes(MultiBranchData::default_count_offset()), - scratch); - - // The method data pointer needs to be updated. - update_mdp_by_offset( - in_bytes(MultiBranchData::default_displacement_offset()), - scratch); - - bind (profile_continue); - } -} - -// Count the index'th case of a switch construct. - -void InterpreterMacroAssembler::profile_switch_case(Register index, - Register scratch, - Register scratch2, - Register scratch3) { - if (ProfileInterpreter) { - Label profile_continue; - - // If no method data exists, go to profile_continue. - test_method_data_pointer(profile_continue); - - // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes() - set(in_bytes(MultiBranchData::per_case_size()), scratch); - smul(index, scratch, scratch); - add(scratch, in_bytes(MultiBranchData::case_array_offset()), scratch); - - // Update the case count - increment_mdp_data_at(scratch, - in_bytes(MultiBranchData::relative_count_offset()), - scratch2, - scratch3); - - // The method data pointer needs to be updated. - update_mdp_by_offset(scratch, - in_bytes(MultiBranchData::relative_displacement_offset()), - scratch2); - - bind (profile_continue); - } -} - -void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr, Register tmp) { - Label not_null, do_nothing, do_update; - - assert_different_registers(obj, mdo_addr.base(), tmp); - - verify_oop(obj); - - ld_ptr(mdo_addr, tmp); - - br_notnull_short(obj, pt, not_null); - or3(tmp, TypeEntries::null_seen, tmp); - ba_short(do_update); - - bind(not_null); - load_klass(obj, obj); - - xor3(obj, tmp, obj); - btst(TypeEntries::type_klass_mask, obj); - // klass seen before, nothing to do. The unknown bit may have been - // set already but no need to check. - brx(zero, false, pt, do_nothing); - delayed()-> - - btst(TypeEntries::type_unknown, obj); - // already unknown. Nothing to do anymore. - brx(notZero, false, pt, do_nothing); - delayed()-> - - btst(TypeEntries::type_mask, tmp); - brx(zero, true, pt, do_update); - // first time here. Set profile type. - delayed()->or3(tmp, obj, tmp); - - // different than before. Cannot keep accurate profile. - or3(tmp, TypeEntries::type_unknown, tmp); - - bind(do_update); - // update profile - st_ptr(tmp, mdo_addr); - - bind(do_nothing); -} - -void InterpreterMacroAssembler::profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual) { - if (!ProfileInterpreter) { - return; - } - - assert_different_registers(callee, tmp1, tmp2, ImethodDataPtr); - - if (MethodData::profile_arguments() || MethodData::profile_return()) { - Label profile_continue; - - test_method_data_pointer(profile_continue); - - int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); - - ldub(ImethodDataPtr, in_bytes(DataLayout::tag_offset()) - off_to_start, tmp1); - cmp_and_br_short(tmp1, is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag, notEqual, pn, profile_continue); - - if (MethodData::profile_arguments()) { - Label done; - int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); - add(ImethodDataPtr, off_to_args, ImethodDataPtr); - - for (int i = 0; i < TypeProfileArgsLimit; i++) { - if (i > 0 || MethodData::profile_return()) { - // If return value type is profiled we may have no argument to profile - ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, tmp1); - sub(tmp1, i*TypeStackSlotEntries::per_arg_count(), tmp1); - cmp_and_br_short(tmp1, TypeStackSlotEntries::per_arg_count(), less, pn, done); - } - ld_ptr(Address(callee, Method::const_offset()), tmp1); - lduh(Address(tmp1, ConstMethod::size_of_parameters_offset()), tmp1); - // stack offset o (zero based) from the start of the argument - // list, for n arguments translates into offset n - o - 1 from - // the end of the argument list. But there's an extra slot at - // the stop of the stack. So the offset is n - o from Lesp. - ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args, tmp2); - sub(tmp1, tmp2, tmp1); - - // Can't use MacroAssembler::argument_address() which needs Gargs to be set up - sll(tmp1, Interpreter::logStackElementSize, tmp1); - ld_ptr(Lesp, tmp1, tmp1); - - Address mdo_arg_addr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); - profile_obj_type(tmp1, mdo_arg_addr, tmp2); - - int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); - add(ImethodDataPtr, to_add, ImethodDataPtr); - off_to_args += to_add; - } - - if (MethodData::profile_return()) { - ld_ptr(ImethodDataPtr, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args, tmp1); - sub(tmp1, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count(), tmp1); - } - - bind(done); - - if (MethodData::profile_return()) { - // We're right after the type profile for the last - // argument. tmp1 is the number of cells left in the - // CallTypeData/VirtualCallTypeData to reach its end. Non null - // if there's a return to profile. - assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); - sll(tmp1, exact_log2(DataLayout::cell_size), tmp1); - add(ImethodDataPtr, tmp1, ImethodDataPtr); - } - } else { - assert(MethodData::profile_return(), "either profile call args or call ret"); - update_mdp_by_constant(in_bytes(TypeEntriesAtCall::return_only_size())); - } - - // mdp points right after the end of the - // CallTypeData/VirtualCallTypeData, right after the cells for the - // return value type if there's one. - - bind(profile_continue); - } -} - -void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, Register tmp2) { - assert_different_registers(ret, tmp1, tmp2); - if (ProfileInterpreter && MethodData::profile_return()) { - Label profile_continue, done; - - test_method_data_pointer(profile_continue); - - if (MethodData::profile_return_jsr292_only()) { - assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); - - // If we don't profile all invoke bytecodes we must make sure - // it's a bytecode we indeed profile. We can't go back to the - // begining of the ProfileData we intend to update to check its - // type because we're right after it and we don't known its - // length. - Label do_profile; - ldub(Lbcp, 0, tmp1); - cmp_and_br_short(tmp1, Bytecodes::_invokedynamic, equal, pn, do_profile); - cmp(tmp1, Bytecodes::_invokehandle); - br(equal, false, pn, do_profile); - delayed()->lduh(Lmethod, Method::intrinsic_id_offset_in_bytes(), tmp1); - cmp_and_br_short(tmp1, vmIntrinsics::_compiledLambdaForm, notEqual, pt, profile_continue); - - bind(do_profile); - } - - Address mdo_ret_addr(ImethodDataPtr, -in_bytes(ReturnTypeEntry::size())); - mov(ret, tmp1); - profile_obj_type(tmp1, mdo_ret_addr, tmp2); - - bind(profile_continue); - } -} - -void InterpreterMacroAssembler::profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4) { - if (ProfileInterpreter && MethodData::profile_parameters()) { - Label profile_continue, done; - - test_method_data_pointer(profile_continue); - - // Load the offset of the area within the MDO used for - // parameters. If it's negative we're not profiling any parameters. - lduw(ImethodDataPtr, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()), tmp1); - cmp_and_br_short(tmp1, 0, less, pn, profile_continue); - - // Compute a pointer to the area for parameters from the offset - // and move the pointer to the slot for the last - // parameters. Collect profiling from last parameter down. - // mdo start + parameters offset + array length - 1 - - // Pointer to the parameter area in the MDO - Register mdp = tmp1; - add(ImethodDataPtr, tmp1, mdp); - - // offset of the current profile entry to update - Register entry_offset = tmp2; - // entry_offset = array len in number of cells - ld_ptr(mdp, ArrayData::array_len_offset(), entry_offset); - - int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); - assert(off_base % DataLayout::cell_size == 0, "should be a number of cells"); - - // entry_offset (number of cells) = array len - size of 1 entry + offset of the stack slot field - sub(entry_offset, TypeStackSlotEntries::per_arg_count() - (off_base / DataLayout::cell_size), entry_offset); - // entry_offset in bytes - sll(entry_offset, exact_log2(DataLayout::cell_size), entry_offset); - - Label loop; - bind(loop); - - // load offset on the stack from the slot for this parameter - ld_ptr(mdp, entry_offset, tmp3); - sll(tmp3,Interpreter::logStackElementSize, tmp3); - neg(tmp3); - // read the parameter from the local area - ld_ptr(Llocals, tmp3, tmp3); - - // make entry_offset now point to the type field for this parameter - int type_base = in_bytes(ParametersTypeData::type_offset(0)); - assert(type_base > off_base, "unexpected"); - add(entry_offset, type_base - off_base, entry_offset); - - // profile the parameter - Address arg_type(mdp, entry_offset); - profile_obj_type(tmp3, arg_type, tmp4); - - // go to next parameter - sub(entry_offset, TypeStackSlotEntries::per_arg_count() * DataLayout::cell_size + (type_base - off_base), entry_offset); - cmp_and_br_short(entry_offset, off_base, greaterEqual, pt, loop); - - bind(profile_continue); - } -} - -// add a InterpMonitorElem to stack (see frame_sparc.hpp) - -void InterpreterMacroAssembler::add_monitor_to_stack( bool stack_is_empty, - Register Rtemp, - Register Rtemp2 ) { - - Register Rlimit = Lmonitors; - const jint delta = frame::interpreter_frame_monitor_size() * wordSize; - assert( (delta & LongAlignmentMask) == 0, - "sizeof BasicObjectLock must be even number of doublewords"); - - sub( SP, delta, SP); - sub( Lesp, delta, Lesp); - sub( Lmonitors, delta, Lmonitors); - - if (!stack_is_empty) { - - // must copy stack contents down - - Label start_copying, next; - - // untested("monitor stack expansion"); - compute_stack_base(Rtemp); - ba(start_copying); - delayed()->cmp(Rtemp, Rlimit); // done? duplicated below - - // note: must copy from low memory upwards - // On entry to loop, - // Rtemp points to new base of stack, Lesp points to new end of stack (1 past TOS) - // Loop mutates Rtemp - - bind( next); - - st_ptr(Rtemp2, Rtemp, 0); - inc(Rtemp, wordSize); - cmp(Rtemp, Rlimit); // are we done? (duplicated above) - - bind( start_copying ); - - brx( notEqual, true, pn, next ); - delayed()->ld_ptr( Rtemp, delta, Rtemp2 ); - - // done copying stack - } -} - -// Locals -void InterpreterMacroAssembler::access_local_ptr( Register index, Register dst ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - ld_ptr(index, 0, dst); - // Note: index must hold the effective address--the iinc template uses it -} - -// Just like access_local_ptr but the tag is a returnAddress -void InterpreterMacroAssembler::access_local_returnAddress(Register index, - Register dst ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - ld_ptr(index, 0, dst); -} - -void InterpreterMacroAssembler::access_local_int( Register index, Register dst ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - ld(index, 0, dst); - // Note: index must hold the effective address--the iinc template uses it -} - - -void InterpreterMacroAssembler::access_local_long( Register index, Register dst ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - // First half stored at index n+1 (which grows down from Llocals[n]) - load_unaligned_long(index, Interpreter::local_offset_in_bytes(1), dst); -} - - -void InterpreterMacroAssembler::access_local_float( Register index, FloatRegister dst ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - ldf(FloatRegisterImpl::S, index, 0, dst); -} - - -void InterpreterMacroAssembler::access_local_double( Register index, FloatRegister dst ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - load_unaligned_double(index, Interpreter::local_offset_in_bytes(1), dst); -} - - -#ifdef ASSERT -void InterpreterMacroAssembler::check_for_regarea_stomp(Register Rindex, int offset, Register Rlimit, Register Rscratch, Register Rscratch1) { - Label L; - - assert(Rindex != Rscratch, "Registers cannot be same"); - assert(Rindex != Rscratch1, "Registers cannot be same"); - assert(Rlimit != Rscratch, "Registers cannot be same"); - assert(Rlimit != Rscratch1, "Registers cannot be same"); - assert(Rscratch1 != Rscratch, "Registers cannot be same"); - - // untested("reg area corruption"); - add(Rindex, offset, Rscratch); - add(Rlimit, 64 + STACK_BIAS, Rscratch1); - cmp_and_brx_short(Rscratch, Rscratch1, Assembler::greaterEqualUnsigned, pn, L); - stop("regsave area is being clobbered"); - bind(L); -} -#endif // ASSERT - - -void InterpreterMacroAssembler::store_local_int( Register index, Register src ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); - debug_only(check_for_regarea_stomp(index, 0, FP, G1_scratch, G4_scratch);) - st(src, index, 0); -} - -void InterpreterMacroAssembler::store_local_ptr( Register index, Register src ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); -#ifdef ASSERT - check_for_regarea_stomp(index, 0, FP, G1_scratch, G4_scratch); -#endif - st_ptr(src, index, 0); -} - - - -void InterpreterMacroAssembler::store_local_ptr( int n, Register src ) { - st_ptr(src, Llocals, Interpreter::local_offset_in_bytes(n)); -} - -void InterpreterMacroAssembler::store_local_long( Register index, Register src ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); -#ifdef ASSERT - check_for_regarea_stomp(index, Interpreter::local_offset_in_bytes(1), FP, G1_scratch, G4_scratch); -#endif - store_unaligned_long(src, index, Interpreter::local_offset_in_bytes(1)); // which is n+1 -} - - -void InterpreterMacroAssembler::store_local_float( Register index, FloatRegister src ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); -#ifdef ASSERT - check_for_regarea_stomp(index, 0, FP, G1_scratch, G4_scratch); -#endif - stf(FloatRegisterImpl::S, src, index, 0); -} - - -void InterpreterMacroAssembler::store_local_double( Register index, FloatRegister src ) { - assert_not_delayed(); - sll(index, Interpreter::logStackElementSize, index); - sub(Llocals, index, index); -#ifdef ASSERT - check_for_regarea_stomp(index, Interpreter::local_offset_in_bytes(1), FP, G1_scratch, G4_scratch); -#endif - store_unaligned_double(src, index, Interpreter::local_offset_in_bytes(1)); -} - - -int InterpreterMacroAssembler::top_most_monitor_byte_offset() { - const jint delta = frame::interpreter_frame_monitor_size() * wordSize; - int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words, WordsPerLong); - return ((-rounded_vm_local_words * wordSize) - delta ) + STACK_BIAS; -} - - -Address InterpreterMacroAssembler::top_most_monitor() { - return Address(FP, top_most_monitor_byte_offset()); -} - - -void InterpreterMacroAssembler::compute_stack_base( Register Rdest ) { - add( Lesp, wordSize, Rdest ); -} - -void InterpreterMacroAssembler::get_method_counters(Register method, - Register Rcounters, - Label& skip) { - Label has_counters; - Address method_counters(method, in_bytes(Method::method_counters_offset())); - ld_ptr(method_counters, Rcounters); - br_notnull_short(Rcounters, Assembler::pt, has_counters); - call_VM(noreg, CAST_FROM_FN_PTR(address, - InterpreterRuntime::build_method_counters), method); - ld_ptr(method_counters, Rcounters); - br_null(Rcounters, false, Assembler::pn, skip); // No MethodCounters, OutOfMemory - delayed()->nop(); - bind(has_counters); -} - -void InterpreterMacroAssembler::increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) { - assert(UseCompiler || LogTouchedMethods, "incrementing must be useful"); - assert_different_registers(Rcounters, Rtmp, Rtmp2); - - Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() + - InvocationCounter::counter_offset()); - Address be_counter (Rcounters, MethodCounters::backedge_counter_offset() + - InvocationCounter::counter_offset()); - int delta = InvocationCounter::count_increment; - - // Load each counter in a register - ld( inv_counter, Rtmp ); - ld( be_counter, Rtmp2 ); - - assert( is_simm13( delta ), " delta too large."); - - // Add the delta to the invocation counter and store the result - add( Rtmp, delta, Rtmp ); - - // Mask the backedge counter - and3( Rtmp2, InvocationCounter::count_mask_value, Rtmp2 ); - - // Store value - st( Rtmp, inv_counter); - - // Add invocation counter + backedge counter - add( Rtmp, Rtmp2, Rtmp); - - // Note that this macro must leave the backedge_count + invocation_count in Rtmp! -} - -void InterpreterMacroAssembler::increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ) { - assert(UseCompiler, "incrementing must be useful"); - assert_different_registers(Rcounters, Rtmp, Rtmp2); - - Address be_counter (Rcounters, MethodCounters::backedge_counter_offset() + - InvocationCounter::counter_offset()); - Address inv_counter(Rcounters, MethodCounters::invocation_counter_offset() + - InvocationCounter::counter_offset()); - - int delta = InvocationCounter::count_increment; - // Load each counter in a register - ld( be_counter, Rtmp ); - ld( inv_counter, Rtmp2 ); - - // Add the delta to the backedge counter - add( Rtmp, delta, Rtmp ); - - // Mask the invocation counter, add to backedge counter - and3( Rtmp2, InvocationCounter::count_mask_value, Rtmp2 ); - - // and store the result to memory - st( Rtmp, be_counter ); - - // Add backedge + invocation counter - add( Rtmp, Rtmp2, Rtmp ); - - // Note that this macro must leave backedge_count + invocation_count in Rtmp! -} - -void InterpreterMacroAssembler::test_backedge_count_for_osr( Register backedge_count, - Register method_counters, - Register branch_bcp, - Register Rtmp ) { - Label did_not_overflow; - Label overflow_with_error; - assert_different_registers(backedge_count, Rtmp, branch_bcp); - assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); - - Address limit(method_counters, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset())); - ld(limit, Rtmp); - cmp_and_br_short(backedge_count, Rtmp, Assembler::lessUnsigned, Assembler::pt, did_not_overflow); - - // When ProfileInterpreter is on, the backedge_count comes from the - // MethodData*, which value does not get reset on the call to - // frequency_counter_overflow(). To avoid excessive calls to the overflow - // routine while the method is being compiled, add a second test to make sure - // the overflow function is called only once every overflow_frequency. - if (ProfileInterpreter) { - const int overflow_frequency = 1024; - andcc(backedge_count, overflow_frequency-1, Rtmp); - brx(Assembler::notZero, false, Assembler::pt, did_not_overflow); - delayed()->nop(); - } - - // overflow in loop, pass branch bytecode - set(6,Rtmp); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, Rtmp); - - // Was an OSR adapter generated? - // O0 = osr nmethod - br_null_short(O0, Assembler::pn, overflow_with_error); - - // Has the nmethod been invalidated already? - ldub(O0, nmethod::state_offset(), O2); - cmp_and_br_short(O2, nmethod::in_use, Assembler::notEqual, Assembler::pn, overflow_with_error); - - // migrate the interpreter frame off of the stack - - mov(G2_thread, L7); - // save nmethod - mov(O0, L6); - set_last_Java_frame(SP, noreg); - call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), L7); - reset_last_Java_frame(); - mov(L7, G2_thread); - - // move OSR nmethod to I1 - mov(L6, I1); - - // OSR buffer to I0 - mov(O0, I0); - - // remove the interpreter frame - restore(I5_savedSP, 0, SP); - - // Jump to the osr code. - ld_ptr(O1, nmethod::osr_entry_point_offset(), O2); - jmp(O2, G0); - delayed()->nop(); - - bind(overflow_with_error); - - bind(did_not_overflow); -} - - - -void InterpreterMacroAssembler::interp_verify_oop(Register reg, TosState state, const char * file, int line) { - if (state == atos) { MacroAssembler::_verify_oop(reg, "broken oop ", file, line); } -} - - -// local helper function for the verify_oop_or_return_address macro -static bool verify_return_address(Method* m, int bci) { -#ifndef PRODUCT - address pc = (address)(m->constMethod()) - + in_bytes(ConstMethod::codes_offset()) + bci; - // assume it is a valid return address if it is inside m and is preceded by a jsr - if (!m->contains(pc)) return false; - address jsr_pc; - jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr); - if (*jsr_pc == Bytecodes::_jsr && jsr_pc >= m->code_base()) return true; - jsr_pc = pc - Bytecodes::length_for(Bytecodes::_jsr_w); - if (*jsr_pc == Bytecodes::_jsr_w && jsr_pc >= m->code_base()) return true; -#endif // PRODUCT - return false; -} - - -void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Register Rtmp) { - if (!VerifyOops) return; - // the VM documentation for the astore[_wide] bytecode allows - // the TOS to be not only an oop but also a return address - Label test; - Label skip; - // See if it is an address (in the current method): - - mov(reg, Rtmp); - const int log2_bytecode_size_limit = 16; - srl(Rtmp, log2_bytecode_size_limit, Rtmp); - br_notnull_short( Rtmp, pt, test ); - - // %%% should use call_VM_leaf here? - save_frame_and_mov(0, Lmethod, O0, reg, O1); - save_thread(L7_thread_cache); - call(CAST_FROM_FN_PTR(address,verify_return_address), relocInfo::none); - delayed()->nop(); - restore_thread(L7_thread_cache); - br_notnull( O0, false, pt, skip ); - delayed()->restore(); - - // Perform a more elaborate out-of-line call - // Not an address; verify it: - bind(test); - verify_oop(reg); - bind(skip); -} - - -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, Address mask_addr, - Register scratch1, Register scratch2, - Condition cond, Label *where) { - ld(counter_addr, scratch1); - add(scratch1, increment, scratch1); - ld(mask_addr, scratch2); - andcc(scratch1, scratch2, G0); - br(cond, false, Assembler::pn, *where); - delayed()->st(scratch1, counter_addr); -} - -// Inline assembly for: -// -// if (thread is in interp_only_mode) { -// InterpreterRuntime::post_method_entry(); -// } -// if (DTraceMethodProbes) { -// SharedRuntime::dtrace_method_entry(method, receiver); -// } -// if (RC_TRACE_IN_RANGE(0x00001000, 0x00002000)) { -// SharedRuntime::rc_trace_method_entry(method, receiver); -// } - -void InterpreterMacroAssembler::notify_method_entry() { - - // Whenever JVMTI puts a thread in interp_only_mode, method - // entry/exit events are sent for that thread to track stack - // depth. If it is possible to enter interp_only_mode we add - // the code to check if the event should be sent. - if (JvmtiExport::can_post_interpreter_events()) { - Label L; - Register temp_reg = O5; - const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); - ld(interp_only, temp_reg); - cmp_and_br_short(temp_reg, 0, equal, pt, L); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry)); - bind(L); - } - - { - Register temp_reg = O5; - SkipIfEqual skip_if(this, temp_reg, &DTraceMethodProbes, zero); - call_VM_leaf(noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), - G2_thread, Lmethod); - } - - // RedefineClasses() tracing support for obsolete method entry - if (log_is_enabled(Trace, redefine, class, obsolete)) { - call_VM_leaf(noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), - G2_thread, Lmethod); - } -} - - -// Inline assembly for: -// -// if (thread is in interp_only_mode) { -// // save result -// InterpreterRuntime::post_method_exit(); -// // restore result -// } -// if (DTraceMethodProbes) { -// SharedRuntime::dtrace_method_exit(thread, method); -// } -// -// Native methods have their result stored in d_tmp and l_tmp -// Java methods have their result stored in the expression stack - -void InterpreterMacroAssembler::notify_method_exit(bool is_native_method, - TosState state, - NotifyMethodExitMode mode) { - - // Whenever JVMTI puts a thread in interp_only_mode, method - // entry/exit events are sent for that thread to track stack - // depth. If it is possible to enter interp_only_mode we add - // the code to check if the event should be sent. - if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { - Label L; - Register temp_reg = O5; - const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); - ld(interp_only, temp_reg); - cmp_and_br_short(temp_reg, 0, equal, pt, L); - - // Note: frame::interpreter_frame_result has a dependency on how the - // method result is saved across the call to post_method_exit. For - // native methods it assumes the result registers are saved to - // l_scratch and d_scratch. If this changes then the interpreter_frame_result - // implementation will need to be updated too. - - save_return_value(state, is_native_method); - call_VM(noreg, - CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); - restore_return_value(state, is_native_method); - bind(L); - } - - { - Register temp_reg = O5; - // Dtrace notification - SkipIfEqual skip_if(this, temp_reg, &DTraceMethodProbes, zero); - save_return_value(state, is_native_method); - call_VM_leaf( - noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - G2_thread, Lmethod); - restore_return_value(state, is_native_method); - } -} - -void InterpreterMacroAssembler::save_return_value(TosState state, bool is_native_call) { - if (is_native_call) { - stf(FloatRegisterImpl::D, F0, d_tmp); - stx(O0, l_tmp); - } else { - push(state); - } -} - -void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_native_call) { - if (is_native_call) { - ldf(FloatRegisterImpl::D, d_tmp, F0); - ldx(l_tmp, O0); - } else { - pop(state); - } -} diff --git a/src/hotspot/cpu/sparc/interp_masm_sparc.hpp b/src/hotspot/cpu/sparc/interp_masm_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/interp_masm_sparc.hpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_INTERP_MASM_SPARC_HPP -#define CPU_SPARC_INTERP_MASM_SPARC_HPP - -#include "asm/macroAssembler.hpp" -#include "interpreter/invocationCounter.hpp" - -// This file specializes the assember with interpreter-specific macros - -typedef ByteSize (*OffsetFunction)(uint); - -REGISTER_DECLARATION( Register, Otos_i , O0); // tos for ints, etc -REGISTER_DECLARATION( Register, Otos_l , O0); // for longs -REGISTER_DECLARATION( Register, Otos_l1, O0); // for 1st part of longs -REGISTER_DECLARATION( Register, Otos_l2, O1); // for 2nd part of longs -REGISTER_DECLARATION(FloatRegister, Ftos_f , F0); // for floats -REGISTER_DECLARATION(FloatRegister, Ftos_d , F0); // for doubles -REGISTER_DECLARATION(FloatRegister, Ftos_d1, F0); // for 1st part of double -REGISTER_DECLARATION(FloatRegister, Ftos_d2, F1); // for 2nd part of double - -class InterpreterMacroAssembler: public MacroAssembler { - protected: - // Interpreter specific version of call_VM_base - virtual void call_VM_leaf_base( - Register java_thread, - 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_exception=true - ); - - // base routine for all dispatches - void dispatch_base(TosState state, address* table); - - public: - InterpreterMacroAssembler(CodeBuffer* c) - : MacroAssembler(c) {} - - virtual void check_and_handle_popframe(Register scratch_reg); - virtual void check_and_handle_earlyret(Register scratch_reg); - - void jump_to_entry(address entry); - - virtual void load_earlyret_value(TosState state); - - static const Address l_tmp ; - static const Address d_tmp ; - - // helper routine for frame allocation/deallocation - // compute the delta by which the caller's SP has to - // be adjusted to accomodate for the non-argument - // locals - void compute_extra_locals_size_in_bytes(Register args_size, Register locals_size, Register delta); - - // dispatch routines - void dispatch_prolog(TosState state, int step = 0); - void dispatch_epilog(TosState state, int step = 0); - void dispatch_only(TosState state); - void dispatch_normal(TosState state); - void dispatch_next(TosState state, int step = 0, bool generate_poll = false); - void dispatch_next_noverify_oop(TosState state, int step = 0); - void dispatch_via (TosState state, address* table); - - - void narrow(Register result); - - // Removes the current activation (incl. unlocking of monitors). - // Additionally this code is used for earlyReturn in which case we - // 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); - - protected: - void dispatch_Lbyte_code(TosState state, address* table, int bcp_incr = 0, bool verify = true, bool generate_poll = false); - - public: - // Super call_VM calls - correspond to MacroAssembler::call_VM(_leaf) calls - void super_call_VM(Register thread_cache, - Register oop_result, - Register last_java_sp, - address entry_point, - Register arg_1, - Register arg_2, - bool check_exception = true); - - void super_call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2); - - // Generate a subtype check: branch to ok_is_subtype if sub_klass is - // a subtype of super_klass. Blows registers tmp1, tmp2 and tmp3. - void gen_subtype_check( Register sub_klass, Register super_klass, Register tmp1, Register tmp2, Register tmp3, Label &ok_is_subtype ); - - // helpers for tossing exceptions - void throw_if_not_1_icc( Condition ok_condition, Label& ok ); - void throw_if_not_1_xcc( Condition ok_condition, Label& ok ); - void throw_if_not_1_x ( Condition ok_condition, Label& ok ); // chooses icc or xcc based on _LP64 - - void throw_if_not_2( address throw_entry_point, Register Rscratch, Label& ok); - - void throw_if_not_icc( Condition ok_condition, address throw_entry_point, Register Rscratch ); - void throw_if_not_xcc( Condition ok_condition, address throw_entry_point, Register Rscratch ); - void throw_if_not_x ( Condition ok_condition, address throw_entry_point, Register Rscratch ); - - // helpers for expression stack - - void pop_i( Register r = Otos_i); - void pop_ptr( Register r = Otos_i, Register scratch = O4); - void pop_l( Register r = Otos_l1); - // G4_scratch and Lscratch are used at call sites!! - void pop_f(FloatRegister f = Ftos_f, Register scratch = G1_scratch); - void pop_d(FloatRegister f = Ftos_d1, Register scratch = G1_scratch); - - void push_i( Register r = Otos_i); - void push_ptr( Register r = Otos_i); - void push_l( Register r = Otos_l1); - void push_f(FloatRegister f = Ftos_f); - void push_d(FloatRegister f = Ftos_d1); - - - void pop (TosState state); // transition vtos -> state - void push(TosState state); // transition state -> vtos - void empty_expression_stack(); // resets both Lesp and SP - -#ifdef ASSERT - void verify_sp(Register Rsp, Register Rtemp); - void verify_esp(Register Resp); // verify that Lesp points to a word in the temp stack -#endif // ASSERT - - public: - void if_cmp(Condition cc, bool ptr_compare); - - // Load values from bytecode stream: - - enum signedOrNot { Signed, Unsigned }; - enum setCCOrNot { set_CC, dont_set_CC }; - - void get_2_byte_integer_at_bcp( int bcp_offset, - Register Rtmp, - Register Rdst, - signedOrNot is_signed, - setCCOrNot should_set_CC = dont_set_CC ); - - void get_4_byte_integer_at_bcp( int bcp_offset, - Register Rtmp, - Register Rdst, - setCCOrNot should_set_CC = dont_set_CC ); - - // Note: "get_cache_and_index" really means "get the index, use it to get the cache entry, and throw away the index". - void get_cache_and_index_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); - void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register temp, 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)); - // Note: This one does not fetch the cache. The first argument is a temp which may be killed. - void get_cache_index_at_bcp(Register temp, Register index, int bcp_offset, size_t index_size = sizeof(u2)); - - // load cpool->resolved_references(index); - void load_resolved_reference_at_index(Register result, Register index, Register tmp); - - // load cpool->resolved_klass_at(index) - void load_resolved_klass_at_offset(Register Rcpool, Register Roffset, Register Rklass); - - // common code - - void field_offset_at(int n, Register tmp, Register dest, Register base); - int field_offset_at(Register object, address bcp, int offset); - void fast_iaaccess(int n, address bcp); - void fast_iaputfield(address bcp, bool do_store_check ); - - void index_check(Register array, Register index, int index_shift, Register tmp, Register res); - void index_check_without_pop(Register array, Register index, int index_shift, Register tmp, Register res); - - void get_const(Register Rdst); - void get_constant_pool(Register Rdst); - void get_constant_pool_cache(Register Rdst); - void get_cpool_and_tags(Register Rcpool, Register Rtags); - void is_a(Label& L); - - // Load compiled (i2c) or interpreter entry and call from interpreted - void call_from_interpreter(Register target, Register scratch, Register Rret); - - // -------------------------------------------------- - - void unlock_if_synchronized_method(TosState state, bool throw_monitor_exception = true, bool install_monitor_exception = true); - - void add_monitor_to_stack( bool stack_is_empty, - Register Rtemp, - Register Rtemp2 ); - - // Load/store aligned in _LP64 but unaligned otherwise - // These only apply to the Interpreter expression stack and locals! - void load_unaligned_double(Register r1, int offset, FloatRegister d); - void store_unaligned_double(FloatRegister d, Register r1, int offset ); - - // Load/store aligned in _LP64 but unaligned otherwise - void load_unaligned_long(Register r1, int offset, Register d); - void store_unaligned_long(Register d, Register r1, int offset ); - - void access_local_int( Register index, Register dst ); - void access_local_ptr( Register index, Register dst ); - void access_local_returnAddress( Register index, Register dst ); - void access_local_long( Register index, Register dst ); - void access_local_float( Register index, FloatRegister dst ); - void access_local_double( Register index, FloatRegister dst ); -#ifdef ASSERT - void check_for_regarea_stomp( Register Rindex, int offset, Register Rlimit, Register Rscratch, Register Rscratch1); -#endif // ASSERT - void store_local_int( Register index, Register src ); - void store_local_ptr( Register index, Register src ); - void store_local_ptr( int n, Register src ); - void store_local_long( Register index, Register src ); - void store_local_float( Register index, FloatRegister src ); - void store_local_double( Register index, FloatRegister src ); - - // Helpers for swap and dup - void load_ptr(int n, Register val); - void store_ptr(int n, Register val); - - // Helper for getting receiver in register. - void load_receiver(Register param_count, Register recv); - - static int top_most_monitor_byte_offset(); // offset in bytes to top of monitor block - Address top_most_monitor(); - void compute_stack_base( Register Rdest ); - - void get_method_counters(Register method, Register Rcounters, Label& skip); - void increment_invocation_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); - void increment_backedge_counter( Register Rcounters, Register Rtmp, Register Rtmp2 ); - void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register branch_bcp, Register Rtmp ); - - // Object locking - void lock_object (Register lock_reg, Register obj_reg); - void unlock_object(Register lock_reg); - - // Interpreter profiling operations - void set_method_data_pointer(); - void set_method_data_pointer_for_bcp(); - void test_method_data_pointer(Label& zero_continue); - void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rtmp, Label &profile_continue); - - void set_mdp_data_at(int constant, Register value); - void increment_mdp_data_at(Address counter, Register bumped_count, - bool decrement = false); - void increment_mdp_data_at(int constant, Register bumped_count, - bool decrement = false); - void increment_mdp_data_at(Register reg, int constant, - Register bumped_count, Register scratch2, - bool decrement = false); - void increment_mask_and_jump(Address counter_addr, - int increment, Address mask_addr, - Register scratch1, Register scratch2, - Condition cond, Label *where); - void set_mdp_flag_at(int flag_constant, Register scratch); - void test_mdp_data_at(int offset, Register value, Label& not_equal_continue, - Register scratch); - - void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call); - void record_klass_in_profile_helper(Register receiver, Register scratch, - Label& done, bool is_virtual_call); - void record_item_in_profile_helper(Register item, - Register scratch, int start_row, Label& done, int total_rows, - OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, - int non_profiled_offset); - - void update_mdp_by_offset(int offset_of_disp, Register scratch); - void update_mdp_by_offset(Register reg, int offset_of_disp, - Register scratch); - void update_mdp_by_constant(int constant); - void update_mdp_for_ret(TosState state, Register return_bci); - - void profile_taken_branch(Register scratch, Register bumped_count); - void profile_not_taken_branch(Register scratch); - void profile_call(Register scratch); - void profile_final_call(Register scratch); - void profile_virtual_call(Register receiver, Register scratch, bool receiver_can_be_null = false); - void profile_ret(TosState state, Register return_bci, Register scratch); - void profile_null_seen(Register scratch); - void profile_typecheck(Register klass, Register scratch); - void profile_typecheck_failed(Register scratch); - void profile_switch_default(Register scratch); - void profile_switch_case(Register index, - Register scratch1, - Register scratch2, - Register scratch3); - - void profile_obj_type(Register obj, const Address& mdo_addr, Register tmp); - void profile_arguments_type(Register callee, Register tmp1, Register tmp2, bool is_virtual); - void profile_return_type(Register ret, Register tmp1, Register tmp2); - void profile_parameters_type(Register tmp1, Register tmp2, Register tmp3, Register tmp4); - - // Debugging - void interp_verify_oop(Register reg, TosState state, const char * file, int line); // only if +VerifyOops && state == atos - void verify_oop_or_return_address(Register reg, Register rtmp); // for astore - void verify_FPU(int stack_depth, TosState state = ftos) {} // No-op. - - // support for JVMTI/Dtrace - typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; - void notify_method_entry(); - void notify_method_exit( - bool save_result, TosState state, NotifyMethodExitMode mode); - - void save_return_value(TosState state, bool is_native_call); - void restore_return_value(TosState state, bool is_native_call); - -}; - -#endif // CPU_SPARC_INTERP_MASM_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp b/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "interpreter/interp_masm.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "memory/allocation.inline.hpp" -#include "oops/method.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/icache.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/signature.hpp" - - -#define __ _masm-> - - -// Implementation of SignatureHandlerGenerator -InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator( - const methodHandle& method, CodeBuffer* buffer) : NativeSignatureIterator(method) { - _masm = new MacroAssembler(buffer); -} - -void InterpreterRuntime::SignatureHandlerGenerator::pass_word(int size_of_arg, int offset_in_arg) { - Argument jni_arg(jni_offset() + offset_in_arg, false); - Register Rtmp = O0; - __ ld(Llocals, Interpreter::local_offset_in_bytes(offset()), Rtmp); - - __ store_argument(Rtmp, jni_arg); -} - -void InterpreterRuntime::SignatureHandlerGenerator::pass_long() { - Argument jni_arg(jni_offset(), false); - Register Rtmp = O0; - - __ ldx(Llocals, Interpreter::local_offset_in_bytes(offset() + 1), Rtmp); - __ store_long_argument(Rtmp, jni_arg); -} - - -void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { - Argument jni_arg(jni_offset(), false); - FloatRegister Rtmp = F0; - __ ldf(FloatRegisterImpl::S, Llocals, Interpreter::local_offset_in_bytes(offset()), Rtmp); - __ store_float_argument(Rtmp, jni_arg); -} - - -void InterpreterRuntime::SignatureHandlerGenerator::pass_double() { - Argument jni_arg(jni_offset(), false); - FloatRegister Rtmp = F0; - __ ldf(FloatRegisterImpl::D, Llocals, Interpreter::local_offset_in_bytes(offset() + 1), Rtmp); - __ store_double_argument(Rtmp, jni_arg); -} - -void InterpreterRuntime::SignatureHandlerGenerator::pass_object() { - Argument jni_arg(jni_offset(), false); - Argument java_arg( offset(), true); - Register Rtmp1 = O0; - Register Rtmp2 = jni_arg.is_register() ? jni_arg.as_register() : O0; - Register Rtmp3 = G3_scratch; - - // the handle for a receiver will never be null - bool do_NULL_check = offset() != 0 || is_static(); - - Address h_arg = Address(Llocals, Interpreter::local_offset_in_bytes(offset())); - __ ld_ptr(h_arg, Rtmp1); - if (!do_NULL_check) { - __ add(h_arg.base(), h_arg.disp(), Rtmp2); - } else { - if (Rtmp1 == Rtmp2) - __ tst(Rtmp1); - else __ addcc(G0, Rtmp1, Rtmp2); // optimize mov/test pair - Label L; - __ brx(Assembler::notZero, true, Assembler::pt, L); - __ delayed()->add(h_arg.base(), h_arg.disp(), Rtmp2); - __ bind(L); - } - __ store_ptr_argument(Rtmp2, jni_arg); // this is often a no-op -} - - -void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) { - - // generate code to handle arguments - iterate(fingerprint); - - // return result handler - AddressLiteral result_handler(Interpreter::result_handler(method()->result_type())); - __ sethi(result_handler, Lscratch); - __ retl(); - __ delayed()->add(Lscratch, result_handler.low10(), Lscratch); - - __ flush(); -} - - -// Implementation of SignatureHandlerLibrary - -void SignatureHandlerLibrary::pd_set_handler(address handler) {} - - -class SlowSignatureHandler: public NativeSignatureIterator { - private: - address _from; - intptr_t* _to; - intptr_t* _RegArgSignature; // Signature of first Arguments to be passed in Registers - uint _argcount; - - enum { // We need to differenciate float from non floats in reg args - non_float = 0, - float_sig = 1, - double_sig = 2, - long_sig = 3 - }; - - virtual void pass_int() { - *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); - _from -= Interpreter::stackElementSize; - add_signature( non_float ); - } - - virtual void pass_object() { - // pass address of from - intptr_t *from_addr = (intptr_t*)(_from + Interpreter::local_offset_in_bytes(0)); - *_to++ = (*from_addr == 0) ? NULL : (intptr_t) from_addr; - _from -= Interpreter::stackElementSize; - add_signature( non_float ); - } - - virtual void pass_float() { - *_to++ = *(jint *)(_from+Interpreter::local_offset_in_bytes(0)); - _from -= Interpreter::stackElementSize; - add_signature( float_sig ); - } - - virtual void pass_double() { - *_to++ = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); - _from -= 2*Interpreter::stackElementSize; - add_signature( double_sig ); - } - - virtual void pass_long() { - _to[0] = *(intptr_t*)(_from+Interpreter::local_offset_in_bytes(1)); - _to += 1; - _from -= 2*Interpreter::stackElementSize; - add_signature( long_sig ); - } - - virtual void add_signature( intptr_t sig_type ) { - if ( _argcount < (sizeof (intptr_t))*4 ) { - *_RegArgSignature |= (sig_type << (_argcount*2) ); - _argcount++; - } - } - - - public: - SlowSignatureHandler(const methodHandle& method, address from, intptr_t* to, intptr_t *RegArgSig) : NativeSignatureIterator(method) { - _from = from; - _to = to; - _RegArgSignature = RegArgSig; - *_RegArgSignature = 0; - _argcount = method->is_static() ? 2 : 1; - } -}; - - -JRT_ENTRY(address, InterpreterRuntime::slow_signature_handler( - JavaThread* thread, - Method* method, - intptr_t* from, - intptr_t* to )) - methodHandle m(thread, method); - assert(m->is_native(), "sanity check"); - // handle arguments - // Warning: We use reg arg slot 00 temporarily to return the RegArgSignature - // back to the code that pops the arguments into the CPU registers - SlowSignatureHandler(m, (address)from, m->is_static() ? to+2 : to+1, to).iterate((uint64_t)CONST64(-1)); - // return result handler - return Interpreter::result_handler(m->result_type()); -JRT_END diff --git a/src/hotspot/cpu/sparc/interpreterRT_sparc.hpp b/src/hotspot/cpu/sparc/interpreterRT_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/interpreterRT_sparc.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef CPU_SPARC_INTERPRETERRT_SPARC_HPP -#define CPU_SPARC_INTERPRETERRT_SPARC_HPP - -// This is included in the middle of class Interpreter. -// Do not include files here. - - -static int binary_search(int key, LookupswitchPair* array, int n); - -static address iload (JavaThread* thread); -static address aload (JavaThread* thread); -static address istore(JavaThread* thread); -static address astore(JavaThread* thread); -static address iinc (JavaThread* thread); - - - -// native method calls - -class SignatureHandlerGenerator: public NativeSignatureIterator { - private: - MacroAssembler* _masm; - - void pass_word(int size_of_arg, int offset_in_arg); - void pass_int() { pass_word(1, 0); } - void pass_long(); - void pass_double(); - void pass_float(); - void pass_object(); - - public: - // Creation - SignatureHandlerGenerator(const methodHandle& method, CodeBuffer* buffer); - - // Code generation - void generate( uint64_t fingerprint ); -}; - -#endif // CPU_SPARC_INTERPRETERRT_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/javaFrameAnchor_sparc.hpp b/src/hotspot/cpu/sparc/javaFrameAnchor_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/javaFrameAnchor_sparc.hpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2002, 2019, 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. - * - */ - -#ifndef CPU_SPARC_JAVAFRAMEANCHOR_SPARC_HPP -#define CPU_SPARC_JAVAFRAMEANCHOR_SPARC_HPP - -private: - volatile int _flags; - -public: - - enum pd_Constants { - flushed = 1 // winodows have flushed - }; - - int flags(void) { return _flags; } - void set_flags(int flags) { _flags = flags; } - - static ByteSize flags_offset() { return byte_offset_of(JavaFrameAnchor, _flags); } - - // Each arch must define clear, copy - // 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; - // fence? - _flags = 0; - _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; - - _flags = src->_flags; - _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; - } - - // Is stack walkable - inline bool walkable( void) { - return _flags & flushed; - } - - void make_walkable(JavaThread* thread); - - void set_last_Java_sp(intptr_t* sp) { _last_Java_sp = sp; } - - address last_Java_pc(void) { return _last_Java_pc; } - - // These are only used by friends -private: - - intptr_t* last_Java_sp() const { - // _last_Java_sp will always be a an unbiased stack pointer - // if is is biased then some setter screwed up. This is - // deadly. - assert(((intptr_t)_last_Java_sp & 0xF) == 0, "Biased last_Java_sp"); - return _last_Java_sp; - } - - void capture_last_Java_pc(intptr_t* sp); - - void set_window_flushed( void) { - _flags |= flushed; - OrderAccess::fence(); - } - -#endif // CPU_SPARC_JAVAFRAMEANCHOR_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp b/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/jniFastGetField_sparc.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2004, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetAssembler.hpp" -#include "memory/resourceArea.hpp" -#include "prims/jniFastGetField.hpp" -#include "prims/jvm_misc.hpp" -#include "runtime/safepoint.hpp" - -// TSO ensures that loads are blocking and ordered with respect to -// to earlier loads, so we don't need LoadLoad membars. - -#define __ masm-> - -#define BUFFER_SIZE 30*sizeof(jint) - -// Common register usage: -// O0: env -// O1: obj -// O2: jfieldID -// O4: offset (O2 >> 2) -// G4: old safepoint counter - -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; - default: ShouldNotReachHere(); - } - ResourceMark rm; - BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); - CodeBuffer cbuf(blob); - MacroAssembler* masm = new MacroAssembler(&cbuf); - address fast_entry = __ pc(); - - Label label1, label2; - - AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr()); - __ sethi (cnt_addrlit, O3); - Address cnt_addr(O3, cnt_addrlit.low10()); - __ ld (cnt_addr, G4); - __ andcc (G4, 1, G0); - __ br (Assembler::notZero, false, Assembler::pn, label1); - __ delayed()->srl (O2, 2, O4); - - if (JvmtiExport::can_post_field_access()) { - // Check to see if a field access watch has been set before we - // take the fast path. - AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr()); - __ load_contents(get_field_access_count_addr, O5); - __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pn, label1); - } - - __ mov(O1, O5); - - // Both O5 and G3 are clobbered by try_resolve_jobject_in_native. - BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G3, label1); - - assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); - speculative_load_pclist[count] = __ pc(); - switch (type) { - case T_BOOLEAN: __ ldub (O5, O4, G3); break; - case T_BYTE: __ ldsb (O5, O4, G3); break; - case T_CHAR: __ lduh (O5, O4, G3); break; - case T_SHORT: __ ldsh (O5, O4, G3); break; - case T_INT: __ ld (O5, O4, G3); break; - default: ShouldNotReachHere(); - } - - __ ld (cnt_addr, O5); - __ cmp (O5, G4); - __ br (Assembler::notEqual, false, Assembler::pn, label2); - __ delayed()->mov (O7, G1); - __ retl (); - __ delayed()->mov (G3, O0); - - slowcase_entry_pclist[count++] = __ pc(); - __ bind (label1); - __ mov (O7, G1); - - 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; - default: ShouldNotReachHere(); - } - __ bind (label2); - __ call (slow_case_addr, relocInfo::none); - __ delayed()->mov (G1, O7); - - __ 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() { - const char *name = "jni_fast_GetLongField"; - ResourceMark rm; - BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE*wordSize); - CodeBuffer cbuf(blob); - MacroAssembler* masm = new MacroAssembler(&cbuf); - address fast_entry = __ pc(); - - Label label1, label2; - - AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr()); - __ sethi (cnt_addrlit, G3); - Address cnt_addr(G3, cnt_addrlit.low10()); - __ ld (cnt_addr, G4); - __ andcc (G4, 1, G0); - __ br (Assembler::notZero, false, Assembler::pn, label1); - __ delayed()->srl (O2, 2, O4); - - if (JvmtiExport::can_post_field_access()) { - // Check to see if a field access watch has been set before we - // take the fast path. - AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr()); - __ load_contents(get_field_access_count_addr, O5); - __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pn, label1); - } - - __ mov(O1, O5); - - // Both O5 and G1 are clobbered by try_resolve_jobject_in_native. - BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G1, label1); - DEBUG_ONLY(__ set(0xDEADC0DE, G1);) - - __ add (O5, O4, O5); - - assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); - speculative_load_pclist[count] = __ pc(); - __ ldx (O5, 0, O3); - - __ ld (cnt_addr, G1); - __ cmp (G1, G4); - __ br (Assembler::notEqual, false, Assembler::pn, label2); - __ delayed()->mov (O7, G1); - - __ retl (); - __ delayed()->mov (O3, O0); - - slowcase_entry_pclist[count++] = __ pc(); - - __ bind (label1); - __ mov (O7, G1); - - address slow_case_addr = jni_GetLongField_addr(); - __ bind (label2); - __ call (slow_case_addr, relocInfo::none); - __ delayed()->mov (G1, O7); - - __ flush (); - - return fast_entry; -} - -address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) { - const char *name; - switch (type) { - 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*wordSize); - CodeBuffer cbuf(blob); - MacroAssembler* masm = new MacroAssembler(&cbuf); - address fast_entry = __ pc(); - - Label label1, label2; - - AddressLiteral cnt_addrlit(SafepointSynchronize::safepoint_counter_addr()); - __ sethi (cnt_addrlit, O3); - Address cnt_addr(O3, cnt_addrlit.low10()); - __ ld (cnt_addr, G4); - __ andcc (G4, 1, G0); - __ br (Assembler::notZero, false, Assembler::pn, label1); - __ delayed()->srl (O2, 2, O4); - - if (JvmtiExport::can_post_field_access()) { - // Check to see if a field access watch has been set before we - // take the fast path. - AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr()); - __ load_contents(get_field_access_count_addr, O5); - __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pn, label1); - } - - __ mov(O1, O5); - - // Both O5 and G3 are clobbered by try_resolve_jobject_in_native. - BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->try_resolve_jobject_in_native(masm, /* jni_env */ O0, /* obj */ O5, /* tmp */ G3, label1); - DEBUG_ONLY(__ set(0xDEADC0DE, G3);) - - assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); - speculative_load_pclist[count] = __ pc(); - switch (type) { - case T_FLOAT: __ ldf (FloatRegisterImpl::S, O5, O4, F0); break; - case T_DOUBLE: __ ldf (FloatRegisterImpl::D, O5, O4, F0); break; - default: ShouldNotReachHere(); - } - - __ ld (cnt_addr, O5); - __ cmp (O5, G4); - __ br (Assembler::notEqual, false, Assembler::pn, label2); - __ delayed()->mov (O7, G1); - - __ retl (); - __ delayed()-> nop (); - - slowcase_entry_pclist[count++] = __ pc(); - __ bind (label1); - __ mov (O7, G1); - - address slow_case_addr; - switch (type) { - case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; - case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; - default: ShouldNotReachHere(); - } - __ bind (label2); - __ call (slow_case_addr, relocInfo::none); - __ delayed()->mov (G1, O7); - - __ flush (); - - return fast_entry; -} - -address JNI_FastGetField::generate_fast_get_float_field() { - return generate_fast_get_float_field0(T_FLOAT); -} - -address JNI_FastGetField::generate_fast_get_double_field() { - return generate_fast_get_float_field0(T_DOUBLE); -} diff --git a/src/hotspot/cpu/sparc/jniTypes_sparc.hpp b/src/hotspot/cpu/sparc/jniTypes_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/jniTypes_sparc.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef CPU_SPARC_JNITYPES_SPARC_HPP -#define CPU_SPARC_JNITYPES_SPARC_HPP - -#include "jni.h" -#include "memory/allocation.hpp" -#include "oops/oop.hpp" - -// 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). - -private: - // Helper routines. - static inline void put_int2 (jint *from, jint *to) { to[0] = from[0]; to[1] = from[1]; } - static inline void put_int2 (jint *from, jint *to, int& pos) { put_int2 (from, (jint *)((intptr_t *)to + pos)); pos += 2; } - static inline void put_int2r(jint *from, jint *to) { to[0] = from[1]; to[1] = from[0]; } - static inline void put_int2r(jint *from, jint *to, int& pos) { put_int2r(from, (jint *)((intptr_t *)to + pos)); pos += 2; } - -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 + 0) = 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; } - - // 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 + 0) = 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. - static inline jint get_int(intptr_t *from) { return *(jint *)from; } - - static inline jlong get_long(intptr_t *from) { return *(jlong *)from; } - - 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; } - -}; - -#endif // CPU_SPARC_JNITYPES_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp b/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (c) 2013, 2019, 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. - */ - -#include "jvmci/jvmciCodeInstaller.hpp" -#include "jvmci/jvmciRuntime.hpp" -#include "jvmci/jvmciCompilerToVM.hpp" -#include "jvmci/jvmciJavaClasses.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "utilities/align.hpp" -#include "vmreg_sparc.inline.hpp" - -jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMCIObject method, JVMCI_TRAPS) { - if (inst->is_call() || inst->is_jump()) { - return pc_offset + NativeCall::instruction_size; - } else if (inst->is_call_reg()) { - return pc_offset + NativeCallReg::instruction_size; - } else if (inst->is_sethi()) { - return pc_offset + NativeFarCall::instruction_size; - } else { - JVMCI_ERROR_0("unsupported type of instruction for call site"); - return 0; - } -} - -void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { - address pc = _instructions->start() + pc_offset; - Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK); - jobject value = JNIHandles::make_local(obj()); - if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) { - int oop_index = _oop_recorder->find_index(value); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - _instructions->relocate(pc, rspec, 1); - } else { - NativeMovConstReg* move = nativeMovConstReg_at(pc); - move->set_data((intptr_t) value); - - // We need two relocations: one on the sethi and one on the add. - int oop_index = _oop_recorder->find_index(value); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - _instructions->relocate(pc + NativeMovConstReg::sethi_offset, rspec); - _instructions->relocate(pc + NativeMovConstReg::add_offset, rspec); - } -} - -void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) { - address pc = _instructions->start() + pc_offset; - if (jvmci_env()->get_HotSpotMetaspaceConstantImpl_compressed(constant)) { - NativeMovConstReg32* move = nativeMovConstReg32_at(pc); - narrowKlass narrowOop = record_narrow_metadata_reference(_instructions, pc, constant, JVMCI_CHECK); - move->set_data((intptr_t)narrowOop); - TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop); - } else { - NativeMovConstReg* move = nativeMovConstReg_at(pc); - void* reference = record_metadata_reference(_instructions, pc, constant, JVMCI_CHECK); - move->set_data((intptr_t)reference); - TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference)); - } -} - -void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, JVMCI_TRAPS) { - address pc = _instructions->start() + pc_offset; - NativeInstruction* inst = nativeInstruction_at(pc); - NativeInstruction* inst1 = nativeInstruction_at(pc + 4); - if(inst->is_sethi() && inst1->is_nop()) { - address const_start = _constants->start(); - address dest = _constants->start() + data_offset; - if(_constants_size > 0) { - _instructions->relocate(pc + NativeMovConstReg::sethi_offset, internal_word_Relocation::spec((address) dest)); - _instructions->relocate(pc + NativeMovConstReg::add_offset, internal_word_Relocation::spec((address) dest)); - } - TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); - }else { - int const_size = align_up(_constants->end()-_constants->start(), CodeEntryAlignment); - NativeMovRegMem* load = nativeMovRegMem_at(pc); - // This offset must match with SPARCLoadConstantTableBaseOp.emitCode - load->set_offset(- (const_size - data_offset + Assembler::min_simm13())); - TRACE_jvmci_3("relocating ld at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); - } -} - -void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, JVMCI_TRAPS) { - address pc = (address) inst; - if (inst->is_call()) { - NativeCall* call = nativeCall_at(pc); - call->set_destination((address) foreign_call_destination); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec()); - } else if (inst->is_sethi()) { - NativeJump* jump = nativeJump_at(pc); - jump->set_jump_destination((address) foreign_call_destination); - _instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec()); - } else { - JVMCI_ERROR("unknown call or jump instruction at " PTR_FORMAT, p2i(pc)); - } - TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst)); -} - -void CodeInstaller::pd_relocate_JavaMethod(CodeBuffer &, JVMCIObject hotspot_method, jint pc_offset, JVMCI_TRAPS) { -#ifdef ASSERT - Method* method = NULL; - // we need to check, this might also be an unresolved method - if (JVMCIENV->isa_HotSpotResolvedJavaMethodImpl(hotspot_method)) { - method = JVMCIENV->asMethod(hotspot_method); - } -#endif - switch (_next_call_type) { - case INLINE_INVOKE: - break; - case INVOKEVIRTUAL: - case INVOKEINTERFACE: { - assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); - call->set_destination(SharedRuntime::get_resolve_virtual_call_stub()); - _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc)); - break; - } - case INVOKESTATIC: { - assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); - call->set_destination(SharedRuntime::get_resolve_static_call_stub()); - _instructions->relocate(call->instruction_address(), relocInfo::static_call_type); - break; - } - case INVOKESPECIAL: { - assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial"); - NativeCall* call = nativeCall_at(_instructions->start() + pc_offset); - call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub()); - _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type); - break; - } - default: - JVMCI_ERROR("invalid _next_call_type value"); - break; - } -} - -void CodeInstaller::pd_relocate_poll(address pc, jint mark, JVMCI_TRAPS) { - switch (mark) { - case POLL_NEAR: - JVMCI_ERROR("unimplemented"); - break; - case POLL_FAR: - _instructions->relocate(pc, relocInfo::poll_type); - break; - case POLL_RETURN_NEAR: - JVMCI_ERROR("unimplemented"); - break; - case POLL_RETURN_FAR: - _instructions->relocate(pc, relocInfo::poll_return_type); - break; - default: - JVMCI_ERROR("invalid mark value"); - break; - } -} - -// convert JVMCI register indices (as used in oop maps) to HotSpot registers -VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, JVMCI_TRAPS) { - // JVMCI Registers are numbered as follows: - // 0..31: Thirty-two General Purpose registers (CPU Registers) - // 32..63: Thirty-two single precision float registers - // 64..95: Thirty-two double precision float registers - // 96..111: Sixteen quad precision float registers - if (jvmci_reg < 32) { - return as_Register(jvmci_reg)->as_VMReg(); - } else { - jint floatRegisterNumber; - if(jvmci_reg < 64) { // Single precision - floatRegisterNumber = jvmci_reg - 32; - } else if(jvmci_reg < 96) { - floatRegisterNumber = 2 * (jvmci_reg - 64); - } else if(jvmci_reg < 112) { - floatRegisterNumber = 4 * (jvmci_reg - 96); - } else { - JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg); - } - return as_FloatRegister(floatRegisterNumber)->as_VMReg(); - } -} - -bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) { - return !hotspotRegister->is_FloatRegister(); -} diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp +++ /dev/null @@ -1,3950 +0,0 @@ -/* - * Copyright (c) 1997, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "jvm.h" -#include "asm/macroAssembler.inline.hpp" -#include "compiler/disassembler.hpp" -#include "gc/shared/collectedHeap.inline.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetAssembler.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/resourceArea.hpp" -#include "memory/universe.hpp" -#include "oops/accessDecorators.hpp" -#include "oops/compressedOops.hpp" -#include "oops/klass.inline.hpp" -#include "prims/methodHandles.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/flags/flagSetting.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/jniHandles.inline.hpp" -#include "runtime/objectMonitor.hpp" -#include "runtime/os.inline.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "utilities/align.hpp" -#include "utilities/macros.hpp" -#include "utilities/powerOfTwo.hpp" - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) /* nothing */ -#define STOP(error) stop(error) -#else -#define BLOCK_COMMENT(str) block_comment(str) -#define STOP(error) block_comment(error); stop(error) -#endif - -// Convert the raw encoding form into the form expected by the -// constructor for Address. -Address Address::make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc) { - assert(scale == 0, "not supported"); - RelocationHolder rspec; - if (disp_reloc != relocInfo::none) { - rspec = Relocation::spec_simple(disp_reloc); - } - - Register rindex = as_Register(index); - if (rindex != G0) { - Address madr(as_Register(base), rindex); - madr._rspec = rspec; - return madr; - } else { - Address madr(as_Register(base), disp); - madr._rspec = rspec; - return madr; - } -} - -Address Argument::address_in_frame() const { - // Warning: In LP64 mode disp will occupy more than 10 bits, but - // op codes such as ld or ldx, only access disp() to get - // their simm13 argument. - int disp = ((_number - Argument::n_register_parameters + frame::memory_parameter_word_sp_offset) * BytesPerWord) + STACK_BIAS; - if (is_in()) - return Address(FP, disp); // In argument. - else - return Address(SP, disp); // Out argument. -} - -static const char* argumentNames[][2] = { - {"A0","P0"}, {"A1","P1"}, {"A2","P2"}, {"A3","P3"}, {"A4","P4"}, - {"A5","P5"}, {"A6","P6"}, {"A7","P7"}, {"A8","P8"}, {"A9","P9"}, - {"A(n>9)","P(n>9)"} -}; - -const char* Argument::name() const { - int nofArgs = sizeof argumentNames / sizeof argumentNames[0]; - int num = number(); - if (num >= nofArgs) num = nofArgs - 1; - return argumentNames[num][is_in() ? 1 : 0]; -} - -#ifdef ASSERT -// On RISC, there's no benefit to verifying instruction boundaries. -bool AbstractAssembler::pd_check_instruction_mark() { return false; } -#endif - -// Patch instruction inst at offset inst_pos to refer to dest_pos -// and return the resulting instruction. -// We should have pcs, not offsets, but since all is relative, it will work out -// OK. -int MacroAssembler::patched_branch(int dest_pos, int inst, int inst_pos) { - int m; // mask for displacement field - int v; // new value for displacement field - const int word_aligned_ones = -4; - switch (inv_op(inst)) { - default: ShouldNotReachHere(); - case call_op: m = wdisp(word_aligned_ones, 0, 30); v = wdisp(dest_pos, inst_pos, 30); break; - case branch_op: - switch (inv_op2(inst)) { - case fbp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break; - case bp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break; - case fb_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break; - case br_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break; - case bpr_op2: { - if (is_cbcond(inst)) { - m = wdisp10(word_aligned_ones, 0); - v = wdisp10(dest_pos, inst_pos); - } else { - m = wdisp16(word_aligned_ones, 0); - v = wdisp16(dest_pos, inst_pos); - } - break; - } - default: ShouldNotReachHere(); - } - } - return inst & ~m | v; -} - -// Return the offset of the branch destionation of instruction inst -// at offset pos. -// Should have pcs, but since all is relative, it works out. -int MacroAssembler::branch_destination(int inst, int pos) { - int r; - switch (inv_op(inst)) { - default: ShouldNotReachHere(); - case call_op: r = inv_wdisp(inst, pos, 30); break; - case branch_op: - switch (inv_op2(inst)) { - case fbp_op2: r = inv_wdisp( inst, pos, 19); break; - case bp_op2: r = inv_wdisp( inst, pos, 19); break; - case fb_op2: r = inv_wdisp( inst, pos, 22); break; - case br_op2: r = inv_wdisp( inst, pos, 22); break; - case bpr_op2: { - if (is_cbcond(inst)) { - r = inv_wdisp10(inst, pos); - } else { - r = inv_wdisp16(inst, pos); - } - break; - } - default: ShouldNotReachHere(); - } - } - return r; -} - -void MacroAssembler::resolve_jobject(Register value, Register tmp) { - Label done, not_weak; - br_null(value, false, Assembler::pn, done); // Use NULL as-is. - delayed()->andcc(value, JNIHandles::weak_tag_mask, G0); // Test for jweak - brx(Assembler::zero, true, Assembler::pt, not_weak); - delayed()->nop(); - access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, - Address(value, -JNIHandles::weak_tag_value), value, tmp); - verify_oop(value); - br (Assembler::always, true, Assembler::pt, done); - delayed()->nop(); - bind(not_weak); - access_load_at(T_OBJECT, IN_NATIVE, Address(value, 0), value, tmp); - verify_oop(value); - bind(done); -} - -void MacroAssembler::null_check(Register reg, int offset) { - if (needs_explicit_null_check((intptr_t)offset)) { - // provoke OS NULL exception if reg = NULL by - // accessing M[reg] w/o changing any registers - ld_ptr(reg, 0, G0); - } - else { - // nothing to do, (later) access of M[reg + offset] - // will provoke OS NULL exception if reg = NULL - } -} - -// Ring buffer jumps - - -void MacroAssembler::jmp2(Register r1, Register r2, const char* file, int line ) { - assert_not_delayed(); - jmpl(r1, r2, G0); -} -void MacroAssembler::jmp(Register r1, int offset, const char* file, int line ) { - assert_not_delayed(); - jmp(r1, offset); -} - -// This code sequence is relocatable to any address, even on LP64. -void MacroAssembler::jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line) { - assert_not_delayed(); - // Force fixed length sethi because NativeJump and NativeFarCall don't handle - // variable length instruction streams. - patchable_sethi(addrlit, temp); - Address a(temp, addrlit.low10() + offset); // Add the offset to the displacement. - jmpl(a.base(), a.disp(), d); -} - -void MacroAssembler::jump(const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line) { - jumpl(addrlit, temp, G0, offset, file, line); -} - - -// Conditional breakpoint (for assertion checks in assembly code) -void MacroAssembler::breakpoint_trap(Condition c, CC cc) { - trap(c, cc, G0, ST_RESERVED_FOR_USER_0); -} - -// We want to use ST_BREAKPOINT here, but the debugger is confused by it. -void MacroAssembler::breakpoint_trap() { - trap(ST_RESERVED_FOR_USER_0); -} - -void MacroAssembler::safepoint_poll(Label& slow_path, bool a, Register thread_reg, Register temp_reg) { - ldx(Address(thread_reg, Thread::polling_page_offset()), temp_reg, 0); - // Armed page has poll bit set. - and3(temp_reg, SafepointMechanism::poll_bit(), temp_reg); - br_notnull(temp_reg, a, Assembler::pn, slow_path); -} - -void MacroAssembler::enter() { - Unimplemented(); -} - -void MacroAssembler::leave() { - Unimplemented(); -} - -// Calls to C land - -#ifdef ASSERT -// a hook for debugging -static Thread* reinitialize_thread() { - return Thread::current(); -} -#else -#define reinitialize_thread Thread::current -#endif - -#ifdef ASSERT -address last_get_thread = NULL; -#endif - -// call this when G2_thread is not known to be valid -void MacroAssembler::get_thread() { - save_frame(0); // to avoid clobbering O0 - mov(G1, L0); // avoid clobbering G1 - mov(G5_method, L1); // avoid clobbering G5 - mov(G3, L2); // avoid clobbering G3 also - mov(G4, L5); // avoid clobbering G4 -#ifdef ASSERT - AddressLiteral last_get_thread_addrlit(&last_get_thread); - set(last_get_thread_addrlit, L3); - rdpc(L4); - inc(L4, 3 * BytesPerInstWord); // skip rdpc + inc + st_ptr to point L4 at call st_ptr(L4, L3, 0); -#endif - call(CAST_FROM_FN_PTR(address, reinitialize_thread), relocInfo::runtime_call_type); - delayed()->nop(); - mov(L0, G1); - mov(L1, G5_method); - mov(L2, G3); - mov(L5, G4); - restore(O0, 0, G2_thread); -} - -static Thread* verify_thread_subroutine(Thread* gthread_value) { - Thread* correct_value = Thread::current(); - guarantee(gthread_value == correct_value, "G2_thread value must be the thread"); - return correct_value; -} - -void MacroAssembler::verify_thread() { - if (VerifyThread) { - // NOTE: this chops off the heads of the 64-bit O registers. - // make sure G2_thread contains the right value - save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod) - mov(G1, L1); // avoid clobbering G1 - // G2 saved below - mov(G3, L3); // avoid clobbering G3 - mov(G4, L4); // avoid clobbering G4 - mov(G5_method, L5); // avoid clobbering G5_method - call(CAST_FROM_FN_PTR(address,verify_thread_subroutine), relocInfo::runtime_call_type); - delayed()->mov(G2_thread, O0); - - mov(L1, G1); // Restore G1 - // G2 restored below - mov(L3, G3); // restore G3 - mov(L4, G4); // restore G4 - mov(L5, G5_method); // restore G5_method - restore(O0, 0, G2_thread); - } -} - - -void MacroAssembler::save_thread(const Register thread_cache) { - verify_thread(); - if (thread_cache->is_valid()) { - assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile"); - mov(G2_thread, thread_cache); - } - if (VerifyThread) { - // smash G2_thread, as if the VM were about to anyway - set(0x67676767, G2_thread); - } -} - - -void MacroAssembler::restore_thread(const Register thread_cache) { - if (thread_cache->is_valid()) { - assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile"); - mov(thread_cache, G2_thread); - verify_thread(); - } else { - // do it the slow way - get_thread(); - } -} - - -// %%% maybe get rid of [re]set_last_Java_frame -void MacroAssembler::set_last_Java_frame(Register last_java_sp, Register last_Java_pc) { - assert_not_delayed(); - Address flags(G2_thread, JavaThread::frame_anchor_offset() + - JavaFrameAnchor::flags_offset()); - Address pc_addr(G2_thread, JavaThread::last_Java_pc_offset()); - - // Always set last_Java_pc and flags first because once last_Java_sp is visible - // has_last_Java_frame is true and users will look at the rest of the fields. - // (Note: flags should always be zero before we get here so doesn't need to be set.) - -#ifdef ASSERT - // Verify that flags was zeroed on return to Java - Label PcOk; - save_frame(0); // to avoid clobbering O0 - ld_ptr(pc_addr, L0); - br_null_short(L0, Assembler::pt, PcOk); - STOP("last_Java_pc not zeroed before leaving Java"); - bind(PcOk); - - // Verify that flags was zeroed on return to Java - Label FlagsOk; - ld(flags, L0); - tst(L0); - br(Assembler::zero, false, Assembler::pt, FlagsOk); - delayed() -> restore(); - STOP("flags not zeroed before leaving Java"); - bind(FlagsOk); -#endif /* ASSERT */ - // - // When returning from calling out from Java mode the frame anchor's last_Java_pc - // will always be set to NULL. It is set here so that if we are doing a call to - // native (not VM) that we capture the known pc and don't have to rely on the - // native call having a standard frame linkage where we can find the pc. - - if (last_Java_pc->is_valid()) { - st_ptr(last_Java_pc, pc_addr); - } - -#ifdef ASSERT - // Make sure that we have an odd stack - Label StackOk; - andcc(last_java_sp, 0x01, G0); - br(Assembler::notZero, false, Assembler::pt, StackOk); - delayed()->nop(); - STOP("Stack Not Biased in set_last_Java_frame"); - bind(StackOk); -#endif // ASSERT - assert( last_java_sp != G4_scratch, "bad register usage in set_last_Java_frame"); - add( last_java_sp, STACK_BIAS, G4_scratch ); - st_ptr(G4_scratch, G2_thread, JavaThread::last_Java_sp_offset()); -} - -void MacroAssembler::reset_last_Java_frame(void) { - assert_not_delayed(); - - Address sp_addr(G2_thread, JavaThread::last_Java_sp_offset()); - Address pc_addr(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset()); - Address flags (G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset()); - -#ifdef ASSERT - // check that it WAS previously set - save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame - ld_ptr(sp_addr, L0); - tst(L0); - breakpoint_trap(Assembler::zero, Assembler::ptr_cc); - restore(); -#endif // ASSERT - - st_ptr(G0, sp_addr); - // Always return last_Java_pc to zero - st_ptr(G0, pc_addr); - // Always null flags after return to Java - st(G0, flags); -} - - -void MacroAssembler::call_VM_base( - Register oop_result, - Register thread_cache, - Register last_java_sp, - address entry_point, - int number_of_arguments, - bool check_exceptions) -{ - assert_not_delayed(); - - // determine last_java_sp register - if (!last_java_sp->is_valid()) { - last_java_sp = SP; - } - // debugging support - assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); - - // 64-bit last_java_sp is biased! - set_last_Java_frame(last_java_sp, noreg); - if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early - save_thread(thread_cache); - // do the call - call(entry_point, relocInfo::runtime_call_type); - if (!VerifyThread) - delayed()->mov(G2_thread, O0); // pass thread as first argument - else - delayed()->nop(); // (thread already passed) - restore_thread(thread_cache); - reset_last_Java_frame(); - - // check for pending exceptions. use Gtemp as scratch register. - if (check_exceptions) { - check_and_forward_exception(Gtemp); - } - -#ifdef ASSERT - set(badHeapWordVal, G3); - set(badHeapWordVal, G4); - set(badHeapWordVal, G5); -#endif - - // get oop result if there is one and reset the value in the thread - if (oop_result->is_valid()) { - get_vm_result(oop_result); - } -} - -void MacroAssembler::check_and_forward_exception(Register scratch_reg) -{ - Label L; - - check_and_handle_popframe(scratch_reg); - check_and_handle_earlyret(scratch_reg); - - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - ld_ptr(exception_addr, scratch_reg); - br_null_short(scratch_reg, pt, L); - // we use O7 linkage so that forward_exception_entry has the issuing PC - call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - delayed()->nop(); - bind(L); -} - - -void MacroAssembler::check_and_handle_popframe(Register scratch_reg) { -} - - -void MacroAssembler::check_and_handle_earlyret(Register scratch_reg) { -} - - -void MacroAssembler::call_VM(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) { - call_VM_base(oop_result, noreg, noreg, entry_point, number_of_arguments, check_exceptions); -} - - -void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) { - // O0 is reserved for the thread - mov(arg_1, O1); - call_VM(oop_result, entry_point, 1, check_exceptions); -} - - -void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) { - // O0 is reserved for the thread - mov(arg_1, O1); - mov(arg_2, O2); assert(arg_2 != O1, "smashed argument"); - call_VM(oop_result, entry_point, 2, check_exceptions); -} - - -void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) { - // O0 is reserved for the thread - mov(arg_1, O1); - mov(arg_2, O2); assert(arg_2 != O1, "smashed argument"); - mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument"); - call_VM(oop_result, entry_point, 3, check_exceptions); -} - - - -// Note: The following call_VM overloadings are useful when a "save" -// has already been performed by a stub, and the last Java frame is -// the previous one. In that case, last_java_sp must be passed as FP -// instead of SP. - - -void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments, bool check_exceptions) { - call_VM_base(oop_result, noreg, last_java_sp, entry_point, number_of_arguments, check_exceptions); -} - - -void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions) { - // O0 is reserved for the thread - mov(arg_1, O1); - call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions); -} - - -void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) { - // O0 is reserved for the thread - mov(arg_1, O1); - mov(arg_2, O2); assert(arg_2 != O1, "smashed argument"); - call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions); -} - - -void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) { - // O0 is reserved for the thread - mov(arg_1, O1); - mov(arg_2, O2); assert(arg_2 != O1, "smashed argument"); - mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument"); - call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions); -} - - - -void MacroAssembler::call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments) { - assert_not_delayed(); - save_thread(thread_cache); - // do the call - call(entry_point, relocInfo::runtime_call_type); - delayed()->nop(); - restore_thread(thread_cache); -#ifdef ASSERT - set(badHeapWordVal, G3); - set(badHeapWordVal, G4); - set(badHeapWordVal, G5); -#endif -} - - -void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments) { - call_VM_leaf_base(thread_cache, entry_point, number_of_arguments); -} - - -void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1) { - mov(arg_1, O0); - call_VM_leaf(thread_cache, entry_point, 1); -} - - -void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) { - mov(arg_1, O0); - mov(arg_2, O1); assert(arg_2 != O0, "smashed argument"); - call_VM_leaf(thread_cache, entry_point, 2); -} - - -void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3) { - mov(arg_1, O0); - mov(arg_2, O1); assert(arg_2 != O0, "smashed argument"); - mov(arg_3, O2); assert(arg_3 != O0 && arg_3 != O1, "smashed argument"); - call_VM_leaf(thread_cache, entry_point, 3); -} - - -void MacroAssembler::get_vm_result(Register oop_result) { - verify_thread(); - Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); - ld_ptr( vm_result_addr, oop_result); - st_ptr(G0, vm_result_addr); - verify_oop(oop_result); -} - - -void MacroAssembler::get_vm_result_2(Register metadata_result) { - verify_thread(); - Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset()); - ld_ptr(vm_result_addr_2, metadata_result); - st_ptr(G0, vm_result_addr_2); -} - - -// We require that C code which does not return a value in vm_result will -// leave it undisturbed. -void MacroAssembler::set_vm_result(Register oop_result) { - verify_thread(); - Address vm_result_addr(G2_thread, JavaThread::vm_result_offset()); - verify_oop(oop_result); - -# ifdef ASSERT - // Check that we are not overwriting any other oop. - save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod - ld_ptr(vm_result_addr, L0); - tst(L0); - restore(); - breakpoint_trap(notZero, Assembler::ptr_cc); - // } -# endif - - st_ptr(oop_result, vm_result_addr); -} - - -void MacroAssembler::ic_call(address entry, bool emit_delay, jint method_index) { - RelocationHolder rspec = virtual_call_Relocation::spec(pc(), method_index); - patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg); - relocate(rspec); - call(entry, relocInfo::none); - if (emit_delay) { - delayed()->nop(); - } -} - - -void MacroAssembler::internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) { - address save_pc; - int shiftcnt; -#ifdef VALIDATE_PIPELINE - assert_no_delay("Cannot put two instructions in delay-slot."); -#endif - v9_dep(); - save_pc = pc(); - - int msb32 = (int) (addrlit.value() >> 32); - int lsb32 = (int) (addrlit.value()); - - if (msb32 == 0 && lsb32 >= 0) { - Assembler::sethi(lsb32, d, addrlit.rspec()); - } - else if (msb32 == -1) { - Assembler::sethi(~lsb32, d, addrlit.rspec()); - xor3(d, ~low10(~0), d); - } - else { - Assembler::sethi(msb32, d, addrlit.rspec()); // msb 22-bits - if (msb32 & 0x3ff) // Any bits? - or3(d, msb32 & 0x3ff, d); // msb 32-bits are now in lsb 32 - if (lsb32 & 0xFFFFFC00) { // done? - if ((lsb32 >> 20) & 0xfff) { // Any bits set? - sllx(d, 12, d); // Make room for next 12 bits - or3(d, (lsb32 >> 20) & 0xfff, d); // Or in next 12 - shiftcnt = 0; // We already shifted - } - else - shiftcnt = 12; - if ((lsb32 >> 10) & 0x3ff) { - sllx(d, shiftcnt + 10, d); // Make room for last 10 bits - or3(d, (lsb32 >> 10) & 0x3ff, d); // Or in next 10 - shiftcnt = 0; - } - else - shiftcnt = 10; - sllx(d, shiftcnt + 10, d); // Shift leaving disp field 0'd - } - else - sllx(d, 32, d); - } - // Pad out the instruction sequence so it can be patched later. - if (ForceRelocatable || (addrlit.rtype() != relocInfo::none && - addrlit.rtype() != relocInfo::runtime_call_type)) { - while (pc() < (save_pc + (7 * BytesPerInstWord))) - nop(); - } -} - - -void MacroAssembler::sethi(const AddressLiteral& addrlit, Register d) { - internal_sethi(addrlit, d, false); -} - - -void MacroAssembler::patchable_sethi(const AddressLiteral& addrlit, Register d) { - internal_sethi(addrlit, d, true); -} - - -int MacroAssembler::insts_for_sethi(address a, bool worst_case) { - if (worst_case) return 7; - intptr_t iaddr = (intptr_t) a; - int msb32 = (int) (iaddr >> 32); - int lsb32 = (int) (iaddr); - int count; - if (msb32 == 0 && lsb32 >= 0) - count = 1; - else if (msb32 == -1) - count = 2; - else { - count = 2; - if (msb32 & 0x3ff) - count++; - if (lsb32 & 0xFFFFFC00 ) { - if ((lsb32 >> 20) & 0xfff) count += 2; - if ((lsb32 >> 10) & 0x3ff) count += 2; - } - } - return count; -} - -int MacroAssembler::worst_case_insts_for_set() { - return insts_for_sethi(NULL, true) + 1; -} - - -// Keep in sync with MacroAssembler::insts_for_internal_set -void MacroAssembler::internal_set(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) { - intptr_t value = addrlit.value(); - - if (!ForceRelocatable && addrlit.rspec().type() == relocInfo::none) { - // can optimize - if (-4096 <= value && value <= 4095) { - or3(G0, value, d); // setsw (this leaves upper 32 bits sign-extended) - return; - } - if (inv_hi22(hi22(value)) == value) { - sethi(addrlit, d); - return; - } - } - assert_no_delay("Cannot put two instructions in delay-slot."); - internal_sethi(addrlit, d, ForceRelocatable); - if (ForceRelocatable || addrlit.rspec().type() != relocInfo::none || addrlit.low10() != 0) { - add(d, addrlit.low10(), d, addrlit.rspec()); - } -} - -// Keep in sync with MacroAssembler::internal_set -int MacroAssembler::insts_for_internal_set(intptr_t value) { - // can optimize - if (-4096 <= value && value <= 4095) { - return 1; - } - if (inv_hi22(hi22(value)) == value) { - return insts_for_sethi((address) value); - } - int count = insts_for_sethi((address) value); - AddressLiteral al(value); - if (al.low10() != 0) { - count++; - } - return count; -} - -void MacroAssembler::set(const AddressLiteral& al, Register d) { - internal_set(al, d, false); -} - -void MacroAssembler::set(intptr_t value, Register d) { - AddressLiteral al(value); - internal_set(al, d, false); -} - -void MacroAssembler::set(address addr, Register d, RelocationHolder const& rspec) { - AddressLiteral al(addr, rspec); - internal_set(al, d, false); -} - -void MacroAssembler::patchable_set(const AddressLiteral& al, Register d) { - internal_set(al, d, true); -} - -void MacroAssembler::patchable_set(intptr_t value, Register d) { - AddressLiteral al(value); - internal_set(al, d, true); -} - - -void MacroAssembler::set64(jlong value, Register d, Register tmp) { - assert_not_delayed(); - v9_dep(); - - int hi = (int)(value >> 32); - int lo = (int)(value & ~0); - int bits_33to2 = (int)((value >> 2) & ~0); - // (Matcher::isSimpleConstant64 knows about the following optimizations.) - if (Assembler::is_simm13(lo) && value == lo) { - or3(G0, lo, d); - } else if (hi == 0) { - Assembler::sethi(lo, d); // hardware version zero-extends to upper 32 - if (low10(lo) != 0) - or3(d, low10(lo), d); - } - else if ((hi >> 2) == 0) { - Assembler::sethi(bits_33to2, d); // hardware version zero-extends to upper 32 - sllx(d, 2, d); - if (low12(lo) != 0) - or3(d, low12(lo), d); - } - else if (hi == -1) { - Assembler::sethi(~lo, d); // hardware version zero-extends to upper 32 - xor3(d, low10(lo) ^ ~low10(~0), d); - } - else if (lo == 0) { - if (Assembler::is_simm13(hi)) { - or3(G0, hi, d); - } else { - Assembler::sethi(hi, d); // hardware version zero-extends to upper 32 - if (low10(hi) != 0) - or3(d, low10(hi), d); - } - sllx(d, 32, d); - } - else { - Assembler::sethi(hi, tmp); - Assembler::sethi(lo, d); // macro assembler version sign-extends - if (low10(hi) != 0) - or3 (tmp, low10(hi), tmp); - if (low10(lo) != 0) - or3 ( d, low10(lo), d); - sllx(tmp, 32, tmp); - or3 (d, tmp, d); - } -} - -int MacroAssembler::insts_for_set64(jlong value) { - v9_dep(); - - int hi = (int) (value >> 32); - int lo = (int) (value & ~0); - int count = 0; - - // (Matcher::isSimpleConstant64 knows about the following optimizations.) - if (Assembler::is_simm13(lo) && value == lo) { - count++; - } else if (hi == 0) { - count++; - if (low10(lo) != 0) - count++; - } - else if (hi == -1) { - count += 2; - } - else if (lo == 0) { - if (Assembler::is_simm13(hi)) { - count++; - } else { - count++; - if (low10(hi) != 0) - count++; - } - count++; - } - else { - count += 2; - if (low10(hi) != 0) - count++; - if (low10(lo) != 0) - count++; - count += 2; - } - return count; -} - -// compute size in bytes of sparc frame, given -// number of extraWords -int MacroAssembler::total_frame_size_in_bytes(int extraWords) { - - int nWords = frame::memory_parameter_word_sp_offset; - - nWords += extraWords; - - if (nWords & 1) ++nWords; // round up to double-word - - return nWords * BytesPerWord; -} - - -// save_frame: given number of "extra" words in frame, -// issue approp. save instruction (p 200, v8 manual) - -void MacroAssembler::save_frame(int extraWords) { - int delta = -total_frame_size_in_bytes(extraWords); - if (is_simm13(delta)) { - save(SP, delta, SP); - } else { - set(delta, G3_scratch); - save(SP, G3_scratch, SP); - } -} - - -void MacroAssembler::save_frame_c1(int size_in_bytes) { - if (is_simm13(-size_in_bytes)) { - save(SP, -size_in_bytes, SP); - } else { - set(-size_in_bytes, G3_scratch); - save(SP, G3_scratch, SP); - } -} - - -void MacroAssembler::save_frame_and_mov(int extraWords, - Register s1, Register d1, - Register s2, Register d2) { - assert_not_delayed(); - - // The trick here is to use precisely the same memory word - // that trap handlers also use to save the register. - // This word cannot be used for any other purpose, but - // it works fine to save the register's value, whether or not - // an interrupt flushes register windows at any given moment! - Address s1_addr; - if (s1->is_valid() && (s1->is_in() || s1->is_local())) { - s1_addr = s1->address_in_saved_window(); - st_ptr(s1, s1_addr); - } - - Address s2_addr; - if (s2->is_valid() && (s2->is_in() || s2->is_local())) { - s2_addr = s2->address_in_saved_window(); - st_ptr(s2, s2_addr); - } - - save_frame(extraWords); - - if (s1_addr.base() == SP) { - ld_ptr(s1_addr.after_save(), d1); - } else if (s1->is_valid()) { - mov(s1->after_save(), d1); - } - - if (s2_addr.base() == SP) { - ld_ptr(s2_addr.after_save(), d2); - } else if (s2->is_valid()) { - mov(s2->after_save(), d2); - } -} - - -AddressLiteral MacroAssembler::allocate_metadata_address(Metadata* obj) { - assert(oop_recorder() != NULL, "this assembler needs a Recorder"); - int index = oop_recorder()->allocate_metadata_index(obj); - RelocationHolder rspec = metadata_Relocation::spec(index); - return AddressLiteral((address)obj, rspec); -} - -AddressLiteral MacroAssembler::constant_metadata_address(Metadata* obj) { - assert(oop_recorder() != NULL, "this assembler needs a Recorder"); - int index = oop_recorder()->find_index(obj); - RelocationHolder rspec = metadata_Relocation::spec(index); - return AddressLiteral((address)obj, rspec); -} - - -AddressLiteral MacroAssembler::constant_oop_address(jobject obj) { -#ifdef ASSERT - { - ThreadInVMfromUnknown tiv; - assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); - assert(Universe::heap()->is_in(JNIHandles::resolve(obj)), "not an oop"); - } -#endif - int oop_index = oop_recorder()->find_index(obj); - return AddressLiteral(obj, oop_Relocation::spec(oop_index)); -} - -void MacroAssembler::set_narrow_oop(jobject obj, Register d) { - assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); - int oop_index = oop_recorder()->find_index(obj); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - - assert_not_delayed(); - // Relocation with special format (see relocInfo_sparc.hpp). - relocate(rspec, 1); - // Assembler::sethi(0x3fffff, d); - emit_int32( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(0x3fffff) ); - // Don't add relocation for 'add'. Do patching during 'sethi' processing. - add(d, 0x3ff, d); - -} - -void MacroAssembler::set_narrow_klass(Klass* k, Register d) { - assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); - int klass_index = oop_recorder()->find_index(k); - RelocationHolder rspec = metadata_Relocation::spec(klass_index); - narrowOop encoded_k = CompressedKlassPointers::encode(k); - - assert_not_delayed(); - // Relocation with special format (see relocInfo_sparc.hpp). - relocate(rspec, 1); - // Assembler::sethi(encoded_k, d); - emit_int32( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(encoded_k) ); - // Don't add relocation for 'add'. Do patching during 'sethi' processing. - add(d, low10(encoded_k), d); - -} - -void MacroAssembler::align(int modulus) { - while (offset() % modulus != 0) nop(); -} - -void RegistersForDebugging::print(outputStream* s) { - FlagSetting fs(Debugging, true); - int j; - for (j = 0; j < 8; ++j) { - if (j != 6) { s->print("i%d = ", j); os::print_location(s, i[j]); } - else { s->print( "fp = " ); os::print_location(s, i[j]); } - } - s->cr(); - - for (j = 0; j < 8; ++j) { - s->print("l%d = ", j); os::print_location(s, l[j]); - } - s->cr(); - - for (j = 0; j < 8; ++j) { - if (j != 6) { s->print("o%d = ", j); os::print_location(s, o[j]); } - else { s->print( "sp = " ); os::print_location(s, o[j]); } - } - s->cr(); - - for (j = 0; j < 8; ++j) { - s->print("g%d = ", j); os::print_location(s, g[j]); - } - s->cr(); - - // print out floats with compression - for (j = 0; j < 32; ) { - jfloat val = f[j]; - int last = j; - for ( ; last+1 < 32; ++last ) { - char b1[1024], b2[1024]; - sprintf(b1, "%f", val); - sprintf(b2, "%f", f[last+1]); - if (strcmp(b1, b2)) - break; - } - s->print("f%d", j); - if ( j != last ) s->print(" - f%d", last); - s->print(" = %f", val); - s->fill_to(25); - s->print_cr(" (0x%x)", *(int*)&val); - j = last + 1; - } - s->cr(); - - // and doubles (evens only) - for (j = 0; j < 32; ) { - jdouble val = d[j]; - int last = j; - for ( ; last+1 < 32; ++last ) { - char b1[1024], b2[1024]; - sprintf(b1, "%f", val); - sprintf(b2, "%f", d[last+1]); - if (strcmp(b1, b2)) - break; - } - s->print("d%d", 2 * j); - if ( j != last ) s->print(" - d%d", last); - s->print(" = %f", val); - s->fill_to(30); - s->print("(0x%x)", *(int*)&val); - s->fill_to(42); - s->print_cr("(0x%x)", *(1 + (int*)&val)); - j = last + 1; - } - s->cr(); -} - -void RegistersForDebugging::save_registers(MacroAssembler* a) { - a->sub(FP, align_up(sizeof(RegistersForDebugging), sizeof(jdouble)) - STACK_BIAS, O0); - a->flushw(); - int i; - for (i = 0; i < 8; ++i) { - a->ld_ptr(as_iRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, i_offset(i)); - a->ld_ptr(as_lRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, l_offset(i)); - a->st_ptr(as_oRegister(i)->after_save(), O0, o_offset(i)); - a->st_ptr(as_gRegister(i)->after_save(), O0, g_offset(i)); - } - for (i = 0; i < 32; ++i) { - a->stf(FloatRegisterImpl::S, as_FloatRegister(i), O0, f_offset(i)); - } - for (i = 0; i < 64; i += 2) { - a->stf(FloatRegisterImpl::D, as_FloatRegister(i), O0, d_offset(i)); - } -} - -void RegistersForDebugging::restore_registers(MacroAssembler* a, Register r) { - for (int i = 1; i < 8; ++i) { - a->ld_ptr(r, g_offset(i), as_gRegister(i)); - } - for (int j = 0; j < 32; ++j) { - a->ldf(FloatRegisterImpl::S, O0, f_offset(j), as_FloatRegister(j)); - } - for (int k = 0; k < 64; k += 2) { - a->ldf(FloatRegisterImpl::D, O0, d_offset(k), as_FloatRegister(k)); - } -} - -void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * file, int line) { - // plausibility check for oops - if (!VerifyOops) return; - - if (reg == G0) return; // always NULL, which is always an oop - - BLOCK_COMMENT("verify_oop {"); - char buffer[64]; -#ifdef COMPILER1 - if (CommentedAssembly) { - snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset()); - block_comment(buffer); - } -#endif - - const char* real_msg = NULL; - { - ResourceMark rm; - stringStream ss; - ss.print("%s at offset %d (%s:%d)", msg, offset(), file, line); - real_msg = code_string(ss.as_string()); - } - - // Call indirectly to solve generation ordering problem - AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address()); - - // Make some space on stack above the current register window. - // Enough to hold 8 64-bit registers. - add(SP,-8*8,SP); - - // Save some 64-bit registers; a normal 'save' chops the heads off - // of 64-bit longs in the 32-bit build. - stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8); - stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8); - mov(reg,O0); // Move arg into O0; arg might be in O7 which is about to be crushed - stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8); - - // Size of set() should stay the same - patchable_set((intptr_t)real_msg, O1); - // Load address to call to into O7 - load_ptr_contents(a, O7); - // Register call to verify_oop_subroutine - callr(O7, G0); - delayed()->nop(); - // recover frame size - add(SP, 8*8,SP); - BLOCK_COMMENT("} verify_oop"); -} - -void MacroAssembler::_verify_oop_addr(Address addr, const char* msg, const char * file, int line) { - // plausibility check for oops - if (!VerifyOops) return; - - const char* real_msg = NULL; - { - ResourceMark rm; - stringStream ss; - ss.print("%s at SP+%d (%s:%d)", msg, addr.disp(), file, line); - real_msg = code_string(ss.as_string()); - } - - // Call indirectly to solve generation ordering problem - AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address()); - - // Make some space on stack above the current register window. - // Enough to hold 8 64-bit registers. - add(SP,-8*8,SP); - - // Save some 64-bit registers; a normal 'save' chops the heads off - // of 64-bit longs in the 32-bit build. - stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8); - stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8); - ld_ptr(addr.base(), addr.disp() + 8*8, O0); // Load arg into O0; arg might be in O7 which is about to be crushed - stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8); - - // Size of set() should stay the same - patchable_set((intptr_t)real_msg, O1); - // Load address to call to into O7 - load_ptr_contents(a, O7); - // Register call to verify_oop_subroutine - callr(O7, G0); - delayed()->nop(); - // recover frame size - add(SP, 8*8,SP); -} - -// side-door communication with signalHandler in os_solaris.cpp -address MacroAssembler::_verify_oop_implicit_branch[3] = { NULL }; - -// This macro is expanded just once; it creates shared code. Contract: -// receives an oop in O0. Must restore O0 & O7 from TLS. Must not smash ANY -// registers, including flags. May not use a register 'save', as this blows -// the high bits of the O-regs if they contain Long values. Acts as a 'leaf' -// call. -void MacroAssembler::verify_oop_subroutine() { - // Leaf call; no frame. - Label succeed, fail, null_or_fail; - - // O0 and O7 were saved already (O0 in O0's TLS home, O7 in O5's TLS home). - // O0 is now the oop to be checked. O7 is the return address. - Register O0_obj = O0; - - // Save some more registers for temps. - stx(O2,SP,frame::register_save_words*wordSize+STACK_BIAS+2*8); - stx(O3,SP,frame::register_save_words*wordSize+STACK_BIAS+3*8); - stx(O4,SP,frame::register_save_words*wordSize+STACK_BIAS+4*8); - stx(O5,SP,frame::register_save_words*wordSize+STACK_BIAS+5*8); - - // Save flags - Register O5_save_flags = O5; - rdccr( O5_save_flags ); - - { // count number of verifies - Register O2_adr = O2; - Register O3_accum = O3; - inc_counter(StubRoutines::verify_oop_count_addr(), O2_adr, O3_accum); - } - - Register O2_mask = O2; - Register O3_bits = O3; - Register O4_temp = O4; - - // mark lower end of faulting range - assert(_verify_oop_implicit_branch[0] == NULL, "set once"); - _verify_oop_implicit_branch[0] = pc(); - - // We can't check the mark oop because it could be in the process of - // locking or unlocking while this is running. - set(Universe::verify_oop_mask (), O2_mask); - set(Universe::verify_oop_bits (), O3_bits); - - // assert((obj & oop_mask) == oop_bits); - and3(O0_obj, O2_mask, O4_temp); - cmp_and_brx_short(O4_temp, O3_bits, notEqual, pn, null_or_fail); - - if ((NULL_WORD & Universe::verify_oop_mask()) == Universe::verify_oop_bits()) { - // the null_or_fail case is useless; must test for null separately - br_null_short(O0_obj, pn, succeed); - } - - // Check the Klass* of this object for being in the right area of memory. - // Cannot do the load in the delay above slot in case O0 is null - load_klass(O0_obj, O0_obj); - // assert((klass != NULL) - br_null_short(O0_obj, pn, fail); - - wrccr( O5_save_flags ); // Restore CCR's - - // mark upper end of faulting range - _verify_oop_implicit_branch[1] = pc(); - - //----------------------- - // all tests pass - bind(succeed); - - // Restore prior 64-bit registers - ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+0*8,O0); - ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+1*8,O1); - ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+2*8,O2); - ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+3*8,O3); - ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+4*8,O4); - ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+5*8,O5); - - retl(); // Leaf return; restore prior O7 in delay slot - delayed()->ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+7*8,O7); - - //----------------------- - bind(null_or_fail); // nulls are less common but OK - br_null(O0_obj, false, pt, succeed); - delayed()->wrccr( O5_save_flags ); // Restore CCR's - - //----------------------- - // report failure: - bind(fail); - _verify_oop_implicit_branch[2] = pc(); - - wrccr( O5_save_flags ); // Restore CCR's - - save_frame(align_up(sizeof(RegistersForDebugging) / BytesPerWord, 2)); - - // stop_subroutine expects message pointer in I1. - mov(I1, O1); - - // Restore prior 64-bit registers - ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+0*8,I0); - ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+1*8,I1); - ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+2*8,I2); - ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+3*8,I3); - ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+4*8,I4); - ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+5*8,I5); - - // factor long stop-sequence into subroutine to save space - assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet"); - - // call indirectly to solve generation ordering problem - AddressLiteral al(StubRoutines::Sparc::stop_subroutine_entry_address()); - load_ptr_contents(al, O5); - jmpl(O5, 0, O7); - delayed()->nop(); -} - - -void MacroAssembler::stop(const char* msg) { - // save frame first to get O7 for return address - // add one word to size in case struct is odd number of words long - // It must be doubleword-aligned for storing doubles into it. - - save_frame(align_up(sizeof(RegistersForDebugging) / BytesPerWord, 2)); - - // stop_subroutine expects message pointer in I1. - // Size of set() should stay the same - patchable_set((intptr_t)msg, O1); - - // factor long stop-sequence into subroutine to save space - assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet"); - - // call indirectly to solve generation ordering problem - AddressLiteral a(StubRoutines::Sparc::stop_subroutine_entry_address()); - load_ptr_contents(a, O5); - jmpl(O5, 0, O7); - delayed()->nop(); - - breakpoint_trap(); // make stop actually stop rather than writing - // unnoticeable results in the output files. - - // restore(); done in callee to save space! -} - - -void MacroAssembler::warn(const char* msg) { - save_frame(align_up(sizeof(RegistersForDebugging) / BytesPerWord, 2)); - RegistersForDebugging::save_registers(this); - mov(O0, L0); - // Size of set() should stay the same - patchable_set((intptr_t)msg, O0); - call( CAST_FROM_FN_PTR(address, warning) ); - delayed()->nop(); -// ret(); -// delayed()->restore(); - RegistersForDebugging::restore_registers(this, L0); - restore(); -} - - -void MacroAssembler::untested(const char* what) { - // We must be able to turn interactive prompting off - // in order to run automated test scripts on the VM - // Use the flag ShowMessageBoxOnError - - const char* b = NULL; - { - ResourceMark rm; - stringStream ss; - ss.print("untested: %s", what); - b = code_string(ss.as_string()); - } - if (ShowMessageBoxOnError) { STOP(b); } - else { warn(b); } -} - - -void MacroAssembler::unimplemented(const char* what) { - const char* buf = NULL; - { - ResourceMark rm; - stringStream ss; - ss.print("unimplemented: %s", what); - buf = code_string(ss.as_string()); - } - stop(buf); -} - - -void MacroAssembler::stop_subroutine() { - RegistersForDebugging::save_registers(this); - - // for the sake of the debugger, stick a PC on the current frame - // (this assumes that the caller has performed an extra "save") - mov(I7, L7); - add(O7, -7 * BytesPerInt, I7); - - save_frame(); // one more save to free up another O7 register - mov(I0, O1); // addr of reg save area - - // We expect pointer to message in I1. Caller must set it up in O1 - mov(I1, O0); // get msg - call (CAST_FROM_FN_PTR(address, MacroAssembler::debug), relocInfo::runtime_call_type); - delayed()->nop(); - - restore(); - - RegistersForDebugging::restore_registers(this, O0); - - save_frame(0); - call(CAST_FROM_FN_PTR(address,breakpoint)); - delayed()->nop(); - restore(); - - mov(L7, I7); - retl(); - delayed()->restore(); // see stop above -} - - -void MacroAssembler::debug(char* msg, RegistersForDebugging* regs) { - if ( ShowMessageBoxOnError ) { - JavaThread* thread = JavaThread::current(); - JavaThreadState saved_state = thread->thread_state(); - thread->set_thread_state(_thread_in_vm); - { - // In order to get locks work, we need to fake a in_VM state - ttyLocker ttyl; - ::tty->print_cr("EXECUTION STOPPED: %s\n", msg); - if (CountBytecodes || TraceBytecodes || StopInterpreterAt) { - BytecodeCounter::print(); - } - if (os::message_box(msg, "Execution stopped, print registers?")) - regs->print(::tty); - } - BREAKPOINT; - ThreadStateTransition::transition(JavaThread::current(), _thread_in_vm, saved_state); - } - else { - ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg); - } - assert(false, "DEBUG MESSAGE: %s", msg); -} - - -void MacroAssembler::calc_mem_param_words(Register Rparam_words, Register Rresult) { - subcc( Rparam_words, Argument::n_register_parameters, Rresult); // how many mem words? - Label no_extras; - br( negative, true, pt, no_extras ); // if neg, clear reg - delayed()->set(0, Rresult); // annuled, so only if taken - bind( no_extras ); -} - - -void MacroAssembler::calc_frame_size(Register Rextra_words, Register Rresult) { - add(Rextra_words, frame::memory_parameter_word_sp_offset, Rresult); - bclr(1, Rresult); - sll(Rresult, LogBytesPerWord, Rresult); // Rresult has total frame bytes -} - - -void MacroAssembler::calc_frame_size_and_save(Register Rextra_words, Register Rresult) { - calc_frame_size(Rextra_words, Rresult); - neg(Rresult); - save(SP, Rresult, SP); -} - - -// --------------------------------------------------------- -Assembler::RCondition cond2rcond(Assembler::Condition c) { - switch (c) { - /*case zero: */ - case Assembler::equal: return Assembler::rc_z; - case Assembler::lessEqual: return Assembler::rc_lez; - case Assembler::less: return Assembler::rc_lz; - /*case notZero:*/ - case Assembler::notEqual: return Assembler::rc_nz; - case Assembler::greater: return Assembler::rc_gz; - case Assembler::greaterEqual: return Assembler::rc_gez; - } - ShouldNotReachHere(); - return Assembler::rc_z; -} - -// compares (32 bit) register with zero and branches. NOT FOR USE WITH 64-bit POINTERS -void MacroAssembler::cmp_zero_and_br(Condition c, Register s1, Label& L, bool a, Predict p) { - tst(s1); - br (c, a, p, L); -} - -// Compares a pointer register with zero and branches on null. -// Does a test & branch on 32-bit systems and a register-branch on 64-bit. -void MacroAssembler::br_null( Register s1, bool a, Predict p, Label& L ) { - assert_not_delayed(); - bpr( rc_z, a, p, s1, L ); -} - -void MacroAssembler::br_notnull( Register s1, bool a, Predict p, Label& L ) { - assert_not_delayed(); - bpr( rc_nz, a, p, s1, L ); -} - -// Compare registers and branch with nop in delay slot or cbcond without delay slot. - -// Compare integer (32 bit) values (icc only). -void MacroAssembler::cmp_and_br_short(Register s1, Register s2, Condition c, - Predict p, Label& L) { - assert_not_delayed(); - if (use_cbcond(L)) { - Assembler::cbcond(c, icc, s1, s2, L); - } else { - cmp(s1, s2); - br(c, false, p, L); - delayed()->nop(); - } -} - -// Compare integer (32 bit) values (icc only). -void MacroAssembler::cmp_and_br_short(Register s1, int simm13a, Condition c, - Predict p, Label& L) { - assert_not_delayed(); - if (is_simm(simm13a,5) && use_cbcond(L)) { - Assembler::cbcond(c, icc, s1, simm13a, L); - } else { - cmp(s1, simm13a); - br(c, false, p, L); - delayed()->nop(); - } -} - -// Branch that tests xcc in LP64 and icc in !LP64 -void MacroAssembler::cmp_and_brx_short(Register s1, Register s2, Condition c, - Predict p, Label& L) { - assert_not_delayed(); - if (use_cbcond(L)) { - Assembler::cbcond(c, ptr_cc, s1, s2, L); - } else { - cmp(s1, s2); - brx(c, false, p, L); - delayed()->nop(); - } -} - -// Branch that tests xcc in LP64 and icc in !LP64 -void MacroAssembler::cmp_and_brx_short(Register s1, int simm13a, Condition c, - Predict p, Label& L) { - assert_not_delayed(); - if (is_simm(simm13a,5) && use_cbcond(L)) { - Assembler::cbcond(c, ptr_cc, s1, simm13a, L); - } else { - cmp(s1, simm13a); - brx(c, false, p, L); - delayed()->nop(); - } -} - -// Short branch version for compares a pointer with zero. - -void MacroAssembler::br_null_short(Register s1, Predict p, Label& L) { - assert_not_delayed(); - if (use_cbcond(L)) { - Assembler::cbcond(zero, ptr_cc, s1, 0, L); - } else { - br_null(s1, false, p, L); - delayed()->nop(); - } -} - -void MacroAssembler::br_notnull_short(Register s1, Predict p, Label& L) { - assert_not_delayed(); - if (use_cbcond(L)) { - Assembler::cbcond(notZero, ptr_cc, s1, 0, L); - } else { - br_notnull(s1, false, p, L); - delayed()->nop(); - } -} - -// Unconditional short branch -void MacroAssembler::ba_short(Label& L) { - assert_not_delayed(); - if (use_cbcond(L)) { - Assembler::cbcond(equal, icc, G0, G0, L); - } else { - br(always, false, pt, L); - delayed()->nop(); - } -} - -// Branch if 'icc' says zero or not (i.e. icc.z == 1|0). - -void MacroAssembler::br_icc_zero(bool iszero, Predict p, Label &L) { - assert_not_delayed(); - Condition cf = (iszero ? Assembler::zero : Assembler::notZero); - br(cf, false, p, L); - delayed()->nop(); -} - -// instruction sequences factored across compiler & interpreter - - -void MacroAssembler::lcmp( Register Ra_hi, Register Ra_low, - Register Rb_hi, Register Rb_low, - Register Rresult) { - - Label check_low_parts, done; - - cmp(Ra_hi, Rb_hi ); // compare hi parts - br(equal, true, pt, check_low_parts); - delayed()->cmp(Ra_low, Rb_low); // test low parts - - // And, with an unsigned comparison, it does not matter if the numbers - // are negative or not. - // E.g., -2 cmp -1: the low parts are 0xfffffffe and 0xffffffff. - // The second one is bigger (unsignedly). - - // Other notes: The first move in each triplet can be unconditional - // (and therefore probably prefetchable). - // And the equals case for the high part does not need testing, - // since that triplet is reached only after finding the high halves differ. - - mov(-1, Rresult); - ba(done); - delayed()->movcc(greater, false, icc, 1, Rresult); - - bind(check_low_parts); - - mov( -1, Rresult); - movcc(equal, false, icc, 0, Rresult); - movcc(greaterUnsigned, false, icc, 1, Rresult); - - bind(done); -} - -void MacroAssembler::lneg( Register Rhi, Register Rlow ) { - subcc( G0, Rlow, Rlow ); - subc( G0, Rhi, Rhi ); -} - -void MacroAssembler::lshl( Register Rin_high, Register Rin_low, - Register Rcount, - Register Rout_high, Register Rout_low, - Register Rtemp ) { - - - Register Ralt_count = Rtemp; - Register Rxfer_bits = Rtemp; - - assert( Ralt_count != Rin_high - && Ralt_count != Rin_low - && Ralt_count != Rcount - && Rxfer_bits != Rin_low - && Rxfer_bits != Rin_high - && Rxfer_bits != Rcount - && Rxfer_bits != Rout_low - && Rout_low != Rin_high, - "register alias checks"); - - Label big_shift, done; - - // This code can be optimized to use the 64 bit shifts in V9. - // Here we use the 32 bit shifts. - - and3( Rcount, 0x3f, Rcount); // take least significant 6 bits - subcc(Rcount, 31, Ralt_count); - br(greater, true, pn, big_shift); - delayed()->dec(Ralt_count); - - // shift < 32 bits, Ralt_count = Rcount-31 - - // We get the transfer bits by shifting right by 32-count the low - // register. This is done by shifting right by 31-count and then by one - // more to take care of the special (rare) case where count is zero - // (shifting by 32 would not work). - - neg(Ralt_count); - - // The order of the next two instructions is critical in the case where - // Rin and Rout are the same and should not be reversed. - - srl(Rin_low, Ralt_count, Rxfer_bits); // shift right by 31-count - if (Rcount != Rout_low) { - sll(Rin_low, Rcount, Rout_low); // low half - } - sll(Rin_high, Rcount, Rout_high); - if (Rcount == Rout_low) { - sll(Rin_low, Rcount, Rout_low); // low half - } - srl(Rxfer_bits, 1, Rxfer_bits ); // shift right by one more - ba(done); - delayed()->or3(Rout_high, Rxfer_bits, Rout_high); // new hi value: or in shifted old hi part and xfer from low - - // shift >= 32 bits, Ralt_count = Rcount-32 - bind(big_shift); - sll(Rin_low, Ralt_count, Rout_high ); - clr(Rout_low); - - bind(done); -} - - -void MacroAssembler::lshr( Register Rin_high, Register Rin_low, - Register Rcount, - Register Rout_high, Register Rout_low, - Register Rtemp ) { - - Register Ralt_count = Rtemp; - Register Rxfer_bits = Rtemp; - - assert( Ralt_count != Rin_high - && Ralt_count != Rin_low - && Ralt_count != Rcount - && Rxfer_bits != Rin_low - && Rxfer_bits != Rin_high - && Rxfer_bits != Rcount - && Rxfer_bits != Rout_high - && Rout_high != Rin_low, - "register alias checks"); - - Label big_shift, done; - - // This code can be optimized to use the 64 bit shifts in V9. - // Here we use the 32 bit shifts. - - and3( Rcount, 0x3f, Rcount); // take least significant 6 bits - subcc(Rcount, 31, Ralt_count); - br(greater, true, pn, big_shift); - delayed()->dec(Ralt_count); - - // shift < 32 bits, Ralt_count = Rcount-31 - - // We get the transfer bits by shifting left by 32-count the high - // register. This is done by shifting left by 31-count and then by one - // more to take care of the special (rare) case where count is zero - // (shifting by 32 would not work). - - neg(Ralt_count); - if (Rcount != Rout_low) { - srl(Rin_low, Rcount, Rout_low); - } - - // The order of the next two instructions is critical in the case where - // Rin and Rout are the same and should not be reversed. - - sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count - sra(Rin_high, Rcount, Rout_high ); // high half - sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more - if (Rcount == Rout_low) { - srl(Rin_low, Rcount, Rout_low); - } - ba(done); - delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high - - // shift >= 32 bits, Ralt_count = Rcount-32 - bind(big_shift); - - sra(Rin_high, Ralt_count, Rout_low); - sra(Rin_high, 31, Rout_high); // sign into hi - - bind( done ); -} - - - -void MacroAssembler::lushr( Register Rin_high, Register Rin_low, - Register Rcount, - Register Rout_high, Register Rout_low, - Register Rtemp ) { - - Register Ralt_count = Rtemp; - Register Rxfer_bits = Rtemp; - - assert( Ralt_count != Rin_high - && Ralt_count != Rin_low - && Ralt_count != Rcount - && Rxfer_bits != Rin_low - && Rxfer_bits != Rin_high - && Rxfer_bits != Rcount - && Rxfer_bits != Rout_high - && Rout_high != Rin_low, - "register alias checks"); - - Label big_shift, done; - - // This code can be optimized to use the 64 bit shifts in V9. - // Here we use the 32 bit shifts. - - and3( Rcount, 0x3f, Rcount); // take least significant 6 bits - subcc(Rcount, 31, Ralt_count); - br(greater, true, pn, big_shift); - delayed()->dec(Ralt_count); - - // shift < 32 bits, Ralt_count = Rcount-31 - - // We get the transfer bits by shifting left by 32-count the high - // register. This is done by shifting left by 31-count and then by one - // more to take care of the special (rare) case where count is zero - // (shifting by 32 would not work). - - neg(Ralt_count); - if (Rcount != Rout_low) { - srl(Rin_low, Rcount, Rout_low); - } - - // The order of the next two instructions is critical in the case where - // Rin and Rout are the same and should not be reversed. - - sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count - srl(Rin_high, Rcount, Rout_high ); // high half - sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more - if (Rcount == Rout_low) { - srl(Rin_low, Rcount, Rout_low); - } - ba(done); - delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high - - // shift >= 32 bits, Ralt_count = Rcount-32 - bind(big_shift); - - srl(Rin_high, Ralt_count, Rout_low); - clr(Rout_high); - - bind( done ); -} - -void MacroAssembler::lcmp( Register Ra, Register Rb, Register Rresult) { - cmp(Ra, Rb); - mov(-1, Rresult); - movcc(equal, false, xcc, 0, Rresult); - movcc(greater, false, xcc, 1, Rresult); -} - - -void MacroAssembler::load_sized_value(Address src, Register dst, size_t size_in_bytes, bool is_signed) { - switch (size_in_bytes) { - case 8: ld_long(src, dst); break; - case 4: ld( src, dst); break; - case 2: is_signed ? ldsh(src, dst) : lduh(src, dst); break; - case 1: is_signed ? ldsb(src, dst) : ldub(src, dst); break; - default: ShouldNotReachHere(); - } -} - -void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in_bytes) { - switch (size_in_bytes) { - case 8: st_long(src, dst); break; - case 4: st( src, dst); break; - case 2: sth( src, dst); break; - case 1: stb( src, dst); break; - default: ShouldNotReachHere(); - } -} - - -void MacroAssembler::float_cmp( bool is_float, int unordered_result, - FloatRegister Fa, FloatRegister Fb, - Register Rresult) { - if (is_float) { - fcmp(FloatRegisterImpl::S, fcc0, Fa, Fb); - } else { - fcmp(FloatRegisterImpl::D, fcc0, Fa, Fb); - } - - if (unordered_result == 1) { - mov( -1, Rresult); - movcc(f_equal, true, fcc0, 0, Rresult); - movcc(f_unorderedOrGreater, true, fcc0, 1, Rresult); - } else { - mov( -1, Rresult); - movcc(f_equal, true, fcc0, 0, Rresult); - movcc(f_greater, true, fcc0, 1, Rresult); - } -} - - -void MacroAssembler::save_all_globals_into_locals() { - mov(G1,L1); - mov(G2,L2); - mov(G3,L3); - mov(G4,L4); - mov(G5,L5); - mov(G6,L6); - mov(G7,L7); -} - -void MacroAssembler::restore_globals_from_locals() { - mov(L1,G1); - mov(L2,G2); - mov(L3,G3); - mov(L4,G4); - mov(L5,G5); - mov(L6,G6); - mov(L7,G7); -} - -RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - intptr_t value = *delayed_value_addr; - if (value != 0) - return RegisterOrConstant(value + offset); - - // load indirectly to solve generation ordering problem - AddressLiteral a(delayed_value_addr); - load_ptr_contents(a, tmp); - -#ifdef ASSERT - tst(tmp); - breakpoint_trap(zero, xcc); -#endif - - if (offset != 0) - add(tmp, offset, tmp); - - return RegisterOrConstant(tmp); -} - - -RegisterOrConstant MacroAssembler::regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) { - assert(d.register_or_noreg() != G0, "lost side effect"); - if ((s2.is_constant() && s2.as_constant() == 0) || - (s2.is_register() && s2.as_register() == G0)) { - // Do nothing, just move value. - if (s1.is_register()) { - if (d.is_constant()) d = temp; - mov(s1.as_register(), d.as_register()); - return d; - } else { - return s1; - } - } - - if (s1.is_register()) { - assert_different_registers(s1.as_register(), temp); - if (d.is_constant()) d = temp; - andn(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register()); - return d; - } else { - if (s2.is_register()) { - assert_different_registers(s2.as_register(), temp); - if (d.is_constant()) d = temp; - set(s1.as_constant(), temp); - andn(temp, s2.as_register(), d.as_register()); - return d; - } else { - intptr_t res = s1.as_constant() & ~s2.as_constant(); - return res; - } - } -} - -RegisterOrConstant MacroAssembler::regcon_inc_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) { - assert(d.register_or_noreg() != G0, "lost side effect"); - if ((s2.is_constant() && s2.as_constant() == 0) || - (s2.is_register() && s2.as_register() == G0)) { - // Do nothing, just move value. - if (s1.is_register()) { - if (d.is_constant()) d = temp; - mov(s1.as_register(), d.as_register()); - return d; - } else { - return s1; - } - } - - if (s1.is_register()) { - assert_different_registers(s1.as_register(), temp); - if (d.is_constant()) d = temp; - add(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register()); - return d; - } else { - if (s2.is_register()) { - assert_different_registers(s2.as_register(), temp); - if (d.is_constant()) d = temp; - add(s2.as_register(), ensure_simm13_or_reg(s1, temp), d.as_register()); - return d; - } else { - intptr_t res = s1.as_constant() + s2.as_constant(); - return res; - } - } -} - -RegisterOrConstant MacroAssembler::regcon_sll_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) { - assert(d.register_or_noreg() != G0, "lost side effect"); - if (!is_simm13(s2.constant_or_zero())) - s2 = (s2.as_constant() & 0xFF); - if ((s2.is_constant() && s2.as_constant() == 0) || - (s2.is_register() && s2.as_register() == G0)) { - // Do nothing, just move value. - if (s1.is_register()) { - if (d.is_constant()) d = temp; - mov(s1.as_register(), d.as_register()); - return d; - } else { - return s1; - } - } - - if (s1.is_register()) { - assert_different_registers(s1.as_register(), temp); - if (d.is_constant()) d = temp; - sll_ptr(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register()); - return d; - } else { - if (s2.is_register()) { - assert_different_registers(s2.as_register(), temp); - if (d.is_constant()) d = temp; - set(s1.as_constant(), temp); - sll_ptr(temp, s2.as_register(), d.as_register()); - return d; - } else { - intptr_t res = s1.as_constant() << s2.as_constant(); - return res; - } - } -} - - -// Look up the method for a megamorphic invokeinterface call. -// The target method is determined by . -// The receiver klass is in recv_klass. -// On success, the result will be in method_result, and execution falls through. -// On failure, execution transfers to the given label. -void MacroAssembler::lookup_interface_method(Register recv_klass, - Register intf_klass, - RegisterOrConstant itable_index, - Register method_result, - Register scan_temp, - Register sethi_temp, - Label& L_no_such_interface, - bool return_method) { - assert_different_registers(recv_klass, intf_klass, method_result, scan_temp); - assert(!return_method || itable_index.is_constant() || itable_index.as_register() == method_result, - "caller must use same register for non-constant itable index as for method"); - - Label L_no_such_interface_restore; - bool did_save = false; - if (scan_temp == noreg || sethi_temp == noreg) { - Register recv_2 = recv_klass->is_global() ? recv_klass : L0; - Register intf_2 = intf_klass->is_global() ? intf_klass : L1; - assert(method_result->is_global(), "must be able to return value"); - scan_temp = L2; - sethi_temp = L3; - save_frame_and_mov(0, recv_klass, recv_2, intf_klass, intf_2); - recv_klass = recv_2; - intf_klass = intf_2; - did_save = true; - } - - // Compute start of first itableOffsetEntry (which is at the end of the vtable) - int vtable_base = in_bytes(Klass::vtable_start_offset()); - int scan_step = itableOffsetEntry::size() * wordSize; - int vte_size = vtableEntry::size_in_bytes(); - - lduw(recv_klass, in_bytes(Klass::vtable_length_offset()), scan_temp); - // %%% We should store the aligned, prescaled offset in the klassoop. - // Then the next several instructions would fold away. - - int itb_offset = vtable_base; - int itb_scale = exact_log2(vtableEntry::size_in_bytes()); - sll(scan_temp, itb_scale, scan_temp); - add(scan_temp, itb_offset, scan_temp); - add(recv_klass, scan_temp, scan_temp); - - if (return_method) { - // Adjust recv_klass by scaled itable_index, so we can free itable_index. - RegisterOrConstant itable_offset = itable_index; - itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset); - itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset); - add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass); - } - - // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) { - // if (scan->interface() == intf) { - // result = (klass + scan->offset() + itable_index); - // } - // } - Label L_search, L_found_method; - - for (int peel = 1; peel >= 0; peel--) { - // %%%% Could load both offset and interface in one ldx, if they were - // in the opposite order. This would save a load. - ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result); - - // Check that this entry is non-null. A null entry means that - // the receiver class doesn't implement the interface, and wasn't the - // same as when the caller was compiled. - bpr(Assembler::rc_z, false, Assembler::pn, method_result, did_save ? L_no_such_interface_restore : L_no_such_interface); - delayed()->cmp(method_result, intf_klass); - - if (peel) { - brx(Assembler::equal, false, Assembler::pt, L_found_method); - } else { - brx(Assembler::notEqual, false, Assembler::pn, L_search); - // (invert the test to fall through to found_method...) - } - delayed()->add(scan_temp, scan_step, scan_temp); - - if (!peel) break; - - bind(L_search); - } - - bind(L_found_method); - - if (return_method) { - // Got a hit. - int ito_offset = itableOffsetEntry::offset_offset_in_bytes(); - // scan_temp[-scan_step] points to the vtable offset we need - ito_offset -= scan_step; - lduw(scan_temp, ito_offset, scan_temp); - ld_ptr(recv_klass, scan_temp, method_result); - } - - if (did_save) { - Label L_done; - ba(L_done); - delayed()->restore(); - - bind(L_no_such_interface_restore); - ba(L_no_such_interface); - delayed()->restore(); - - bind(L_done); - } -} - - -// virtual method calling -void MacroAssembler::lookup_virtual_method(Register recv_klass, - RegisterOrConstant vtable_index, - Register method_result) { - assert_different_registers(recv_klass, method_result, vtable_index.register_or_noreg()); - Register sethi_temp = method_result; - const int base = in_bytes(Klass::vtable_start_offset()) + - // method pointer offset within the vtable entry: - vtableEntry::method_offset_in_bytes(); - RegisterOrConstant vtable_offset = vtable_index; - // Each of the following three lines potentially generates an instruction. - // But the total number of address formation instructions will always be - // at most two, and will often be zero. In any case, it will be optimal. - // If vtable_index is a register, we will have (sll_ptr N,x; inc_ptr B,x; ld_ptr k,x). - // If vtable_index is a constant, we will have at most (set B+X<is_global()) sub_2 = L0; - if (!sup_2->is_global()) sup_2 = L1; - bool did_save = false; - if (temp_reg == noreg || temp2_reg == noreg) { - temp_reg = L2; - temp2_reg = L3; - save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2); - sub_klass = sub_2; - super_klass = sup_2; - did_save = true; - } - Label L_failure, L_pop_to_failure, L_pop_to_success; - check_klass_subtype_fast_path(sub_klass, super_klass, - temp_reg, temp2_reg, - (did_save ? &L_pop_to_success : &L_success), - (did_save ? &L_pop_to_failure : &L_failure), NULL); - - if (!did_save) - save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2); - check_klass_subtype_slow_path(sub_2, sup_2, - L2, L3, L4, L5, - NULL, &L_pop_to_failure); - - // on success: - bind(L_pop_to_success); - restore(); - ba_short(L_success); - - // on failure: - bind(L_pop_to_failure); - restore(); - bind(L_failure); -} - - -void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, - Register super_klass, - Register temp_reg, - Register temp2_reg, - Label* L_success, - Label* L_failure, - Label* L_slow_path, - RegisterOrConstant super_check_offset) { - int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); - int sco_offset = in_bytes(Klass::super_check_offset_offset()); - - bool must_load_sco = (super_check_offset.constant_or_zero() == -1); - bool need_slow_path = (must_load_sco || - super_check_offset.constant_or_zero() == sco_offset); - - assert_different_registers(sub_klass, super_klass, temp_reg); - if (super_check_offset.is_register()) { - assert_different_registers(sub_klass, super_klass, temp_reg, - super_check_offset.as_register()); - } else if (must_load_sco) { - assert(temp2_reg != noreg, "supply either a temp or a register offset"); - } - - Label L_fallthrough; - int label_nulls = 0; - if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } - if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } - if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } - assert(label_nulls <= 1 || - (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path), - "at most one NULL in the batch, usually"); - - // If the pointers are equal, we are done (e.g., String[] elements). - // This self-check enables sharing of secondary supertype arrays among - // non-primary types such as array-of-interface. Otherwise, each such - // type would need its own customized SSA. - // We move this check to the front of the fast path because many - // type checks are in fact trivially successful in this manner, - // so we get a nicely predicted branch right at the start of the check. - cmp(super_klass, sub_klass); - brx(Assembler::equal, false, Assembler::pn, *L_success); - delayed()->nop(); - - // Check the supertype display: - if (must_load_sco) { - // The super check offset is always positive... - lduw(super_klass, sco_offset, temp2_reg); - super_check_offset = RegisterOrConstant(temp2_reg); - // super_check_offset is register. - assert_different_registers(sub_klass, super_klass, temp_reg, super_check_offset.as_register()); - } - ld_ptr(sub_klass, super_check_offset, temp_reg); - cmp(super_klass, temp_reg); - - // This check has worked decisively for primary supers. - // Secondary supers are sought in the super_cache ('super_cache_addr'). - // (Secondary supers are interfaces and very deeply nested subtypes.) - // This works in the same check above because of a tricky aliasing - // between the super_cache and the primary super display elements. - // (The 'super_check_addr' can address either, as the case requires.) - // Note that the cache is updated below if it does not help us find - // what we need immediately. - // So if it was a primary super, we can just fail immediately. - // Otherwise, it's the slow path for us (no success at this point). - - // Hacked ba(), which may only be used just before L_fallthrough. -#define FINAL_JUMP(label) \ - if (&(label) != &L_fallthrough) { \ - ba(label); delayed()->nop(); \ - } - - if (super_check_offset.is_register()) { - brx(Assembler::equal, false, Assembler::pn, *L_success); - delayed()->cmp(super_check_offset.as_register(), sc_offset); - - if (L_failure == &L_fallthrough) { - brx(Assembler::equal, false, Assembler::pt, *L_slow_path); - delayed()->nop(); - } else { - brx(Assembler::notEqual, false, Assembler::pn, *L_failure); - delayed()->nop(); - FINAL_JUMP(*L_slow_path); - } - } else if (super_check_offset.as_constant() == sc_offset) { - // Need a slow path; fast failure is impossible. - if (L_slow_path == &L_fallthrough) { - brx(Assembler::equal, false, Assembler::pt, *L_success); - delayed()->nop(); - } else { - brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path); - delayed()->nop(); - FINAL_JUMP(*L_success); - } - } else { - // No slow path; it's a fast decision. - if (L_failure == &L_fallthrough) { - brx(Assembler::equal, false, Assembler::pt, *L_success); - delayed()->nop(); - } else { - brx(Assembler::notEqual, false, Assembler::pn, *L_failure); - delayed()->nop(); - FINAL_JUMP(*L_success); - } - } - - bind(L_fallthrough); - -#undef FINAL_JUMP -} - - -void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, - Register super_klass, - Register count_temp, - Register scan_temp, - Register scratch_reg, - Register coop_reg, - Label* L_success, - Label* L_failure) { - assert_different_registers(sub_klass, super_klass, - count_temp, scan_temp, scratch_reg, coop_reg); - - Label L_fallthrough, L_loop; - int label_nulls = 0; - if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } - if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } - assert(label_nulls <= 1, "at most one NULL in the batch"); - - // a couple of useful fields in sub_klass: - int ss_offset = in_bytes(Klass::secondary_supers_offset()); - int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); - - // Do a linear scan of the secondary super-klass chain. - // This code is rarely used, so simplicity is a virtue here. - -#ifndef PRODUCT - int* pst_counter = &SharedRuntime::_partial_subtype_ctr; - inc_counter((address) pst_counter, count_temp, scan_temp); -#endif - - // We will consult the secondary-super array. - ld_ptr(sub_klass, ss_offset, scan_temp); - - Register search_key = super_klass; - - // Load the array length. (Positive movl does right thing on LP64.) - lduw(scan_temp, Array::length_offset_in_bytes(), count_temp); - - // Check for empty secondary super list - tst(count_temp); - - // In the array of super classes elements are pointer sized. - int element_size = wordSize; - - // Top of search loop - bind(L_loop); - br(Assembler::equal, false, Assembler::pn, *L_failure); - delayed()->add(scan_temp, element_size, scan_temp); - - // Skip the array header in all array accesses. - int elem_offset = Array::base_offset_in_bytes(); - elem_offset -= element_size; // the scan pointer was pre-incremented also - - // Load next super to check - ld_ptr( scan_temp, elem_offset, scratch_reg ); - - // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list - cmp(scratch_reg, search_key); - - // A miss means we are NOT a subtype and need to keep looping - brx(Assembler::notEqual, false, Assembler::pn, L_loop); - delayed()->deccc(count_temp); // decrement trip counter in delay slot - - // Success. Cache the super we found and proceed in triumph. - st_ptr(super_klass, sub_klass, sc_offset); - - if (L_success != &L_fallthrough) { - ba(*L_success); - delayed()->nop(); - } - - bind(L_fallthrough); -} - - -RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot, - Register temp_reg, - int extra_slot_offset) { - // cf. TemplateTable::prepare_invoke(), if (load_receiver). - int stackElementSize = Interpreter::stackElementSize; - int offset = extra_slot_offset * stackElementSize; - if (arg_slot.is_constant()) { - offset += arg_slot.as_constant() * stackElementSize; - return offset; - } else { - assert(temp_reg != noreg, "must specify"); - sll_ptr(arg_slot.as_register(), exact_log2(stackElementSize), temp_reg); - if (offset != 0) - add(temp_reg, offset, temp_reg); - return temp_reg; - } -} - - -Address MacroAssembler::argument_address(RegisterOrConstant arg_slot, - Register temp_reg, - int extra_slot_offset) { - return Address(Gargs, argument_offset(arg_slot, temp_reg, extra_slot_offset)); -} - - -void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg, - Register temp_reg, - Label& done, Label* slow_case, - BiasedLockingCounters* counters) { - assert(UseBiasedLocking, "why call this otherwise?"); - - if (PrintBiasedLockingStatistics) { - assert_different_registers(obj_reg, mark_reg, temp_reg, O7); - if (counters == NULL) - counters = BiasedLocking::counters(); - } - - Label cas_label; - - // Biased locking - // See whether the lock is currently biased toward our thread and - // whether the epoch is still valid - // Note that the runtime guarantees sufficient alignment of JavaThread - // pointers to allow age to be placed into low bits - assert(markWord::age_shift == markWord::lock_bits + markWord::biased_lock_bits, "biased locking makes assumptions about bit layout"); - and3(mark_reg, markWord::biased_lock_mask_in_place, temp_reg); - cmp_and_brx_short(temp_reg, markWord::biased_lock_pattern, Assembler::notEqual, Assembler::pn, cas_label); - - load_klass(obj_reg, temp_reg); - ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg); - or3(G2_thread, temp_reg, temp_reg); - xor3(mark_reg, temp_reg, temp_reg); - andcc(temp_reg, ~((int) markWord::age_mask_in_place), temp_reg); - if (counters != NULL) { - cond_inc(Assembler::equal, (address) counters->biased_lock_entry_count_addr(), mark_reg, temp_reg); - // Reload mark_reg as we may need it later - ld_ptr(Address(obj_reg, oopDesc::mark_offset_in_bytes()), mark_reg); - } - brx(Assembler::equal, true, Assembler::pt, done); - delayed()->nop(); - - Label try_revoke_bias; - Label try_rebias; - Address mark_addr = Address(obj_reg, oopDesc::mark_offset_in_bytes()); - assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - - // At this point we know that the header has the bias pattern and - // that we are not the bias owner in the current epoch. We need to - // figure out more details about the state of the header in order to - // know what operations can be legally performed on the object's - // header. - - // If the low three bits in the xor result aren't clear, that means - // the prototype header is no longer biased and we have to revoke - // the bias on this object. - btst(markWord::biased_lock_mask_in_place, temp_reg); - brx(Assembler::notZero, false, Assembler::pn, try_revoke_bias); - - // Biasing is still enabled for this data type. See whether the - // epoch of the current bias is still valid, meaning that the epoch - // bits of the mark word are equal to the epoch bits of the - // prototype header. (Note that the prototype header's epoch bits - // only change at a safepoint.) If not, attempt to rebias the object - // toward the current thread. Note that we must be absolutely sure - // that the current epoch is invalid in order to do this because - // otherwise the manipulations it performs on the mark word are - // illegal. - delayed()->btst(markWord::epoch_mask_in_place, temp_reg); - brx(Assembler::notZero, false, Assembler::pn, try_rebias); - - // The epoch of the current bias is still valid but we know nothing - // about the owner; it might be set or it might be clear. Try to - // acquire the bias of the object using an atomic operation. If this - // fails we will go in to the runtime to revoke the object's bias. - // Note that we first construct the presumed unbiased header so we - // don't accidentally blow away another thread's valid bias. - delayed()->and3(mark_reg, - markWord::biased_lock_mask_in_place | markWord::age_mask_in_place | markWord::epoch_mask_in_place, - mark_reg); - or3(G2_thread, mark_reg, temp_reg); - cas_ptr(mark_addr.base(), mark_reg, temp_reg); - // If the biasing toward our thread failed, this means that - // another thread succeeded in biasing it toward itself and we - // need to revoke that bias. The revocation will occur in the - // interpreter runtime in the slow case. - cmp(mark_reg, temp_reg); - if (counters != NULL) { - cond_inc(Assembler::zero, (address) counters->anonymously_biased_lock_entry_count_addr(), mark_reg, temp_reg); - } - if (slow_case != NULL) { - brx(Assembler::notEqual, true, Assembler::pn, *slow_case); - delayed()->nop(); - } - ba_short(done); - - bind(try_rebias); - // At this point we know the epoch has expired, meaning that the - // current "bias owner", if any, is actually invalid. Under these - // circumstances _only_, we are allowed to use the current header's - // value as the comparison value when doing the cas to acquire the - // bias in the current epoch. In other words, we allow transfer of - // the bias from one thread to another directly in this situation. - // - // FIXME: due to a lack of registers we currently blow away the age - // bits in this situation. Should attempt to preserve them. - load_klass(obj_reg, temp_reg); - ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg); - or3(G2_thread, temp_reg, temp_reg); - cas_ptr(mark_addr.base(), mark_reg, temp_reg); - // If the biasing toward our thread failed, this means that - // another thread succeeded in biasing it toward itself and we - // need to revoke that bias. The revocation will occur in the - // interpreter runtime in the slow case. - cmp(mark_reg, temp_reg); - if (counters != NULL) { - cond_inc(Assembler::zero, (address) counters->rebiased_lock_entry_count_addr(), mark_reg, temp_reg); - } - if (slow_case != NULL) { - brx(Assembler::notEqual, true, Assembler::pn, *slow_case); - delayed()->nop(); - } - ba_short(done); - - bind(try_revoke_bias); - // The prototype mark in the klass doesn't have the bias bit set any - // more, indicating that objects of this data type are not supposed - // to be biased any more. We are going to try to reset the mark of - // this object to the prototype value and fall through to the - // CAS-based locking scheme. Note that if our CAS fails, it means - // that another thread raced us for the privilege of revoking the - // bias of this particular object, so it's okay to continue in the - // normal locking code. - // - // FIXME: due to a lack of registers we currently blow away the age - // bits in this situation. Should attempt to preserve them. - load_klass(obj_reg, temp_reg); - ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg); - cas_ptr(mark_addr.base(), mark_reg, temp_reg); - // Fall through to the normal CAS-based lock, because no matter what - // the result of the above CAS, some thread must have succeeded in - // removing the bias bit from the object's header. - if (counters != NULL) { - cmp(mark_reg, temp_reg); - cond_inc(Assembler::zero, (address) counters->revoked_lock_entry_count_addr(), mark_reg, temp_reg); - } - - bind(cas_label); -} - -void MacroAssembler::biased_locking_exit (Address mark_addr, Register temp_reg, Label& done, - bool allow_delay_slot_filling) { - // Check for biased locking unlock case, which is a no-op - // Note: we do not have to check the thread ID for two reasons. - // First, the interpreter checks for IllegalMonitorStateException at - // a higher level. Second, if the bias was revoked while we held the - // lock, the object could not be rebiased toward another thread, so - // the bias bit would be clear. - ld_ptr(mark_addr, temp_reg); - and3(temp_reg, markWord::biased_lock_mask_in_place, temp_reg); - cmp(temp_reg, markWord::biased_lock_pattern); - brx(Assembler::equal, allow_delay_slot_filling, Assembler::pt, done); - delayed(); - if (!allow_delay_slot_filling) { - nop(); - } -} - - -// compiler_lock_object() and compiler_unlock_object() are direct transliterations -// of i486.ad fast_lock() and fast_unlock(). See those methods for detailed comments. -// The code could be tightened up considerably. -// -// box->dhw disposition - post-conditions at DONE_LABEL. -// - Successful inflated lock: box->dhw != 0. -// Any non-zero value suffices. -// Consider G2_thread, rsp, boxReg, or markWord::unused_mark() -// - Successful Stack-lock: box->dhw == mark. -// box->dhw must contain the displaced mark word value -// - Failure -- icc.ZFlag == 0 and box->dhw is undefined. -// The slow-path enter() is responsible for setting -// box->dhw = NonZero (typically markWord::unused_mark()). -// - Biased: box->dhw is undefined -// -// SPARC refworkload performance - specifically jetstream and scimark - are -// extremely sensitive to the size of the code emitted by compiler_lock_object -// and compiler_unlock_object. Critically, the key factor is code size, not path -// length. (Simply experiments to pad CLO with unexecuted NOPs demonstrte the -// effect). - - -void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark, - Register Rbox, Register Rscratch, - BiasedLockingCounters* counters, - bool try_bias) { - Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); - - verify_oop(Roop); - Label done ; - - if (counters != NULL) { - inc_counter((address) counters->total_entry_count_addr(), Rmark, Rscratch); - } - - // Aggressively avoid the Store-before-CAS penalty - // Defer the store into box->dhw until after the CAS - Label IsInflated, Recursive ; - -// Anticipate CAS -- Avoid RTS->RTO upgrade -// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads); - - ld_ptr(mark_addr, Rmark); // fetch obj->mark - // Triage: biased, stack-locked, neutral, inflated - - if (try_bias) { - biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters); - // Invariant: if control reaches this point in the emitted stream - // then Rmark has not been modified. - } - andcc(Rmark, 2, G0); - brx(Assembler::notZero, false, Assembler::pn, IsInflated); - delayed()-> // Beware - dangling delay-slot - - // Try stack-lock acquisition. - // Transiently install BUSY (0) encoding in the mark word. - // if the CAS of 0 into the mark was successful then we execute: - // ST box->dhw = mark -- save fetched mark in on-stack basiclock box - // ST obj->mark = box -- overwrite transient 0 value - // This presumes TSO, of course. - - mov(0, Rscratch); - or3(Rmark, markWord::unlocked_value, Rmark); - assert(mark_addr.disp() == 0, "cas must take a zero displacement"); - cas_ptr(mark_addr.base(), Rmark, Rscratch); -// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads); - cmp(Rscratch, Rmark); - brx(Assembler::notZero, false, Assembler::pn, Recursive); - delayed()->st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes()); - if (counters != NULL) { - cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch); - } - ba(done); - delayed()->st_ptr(Rbox, mark_addr); - - bind(Recursive); - // Stack-lock attempt failed - check for recursive stack-lock. - // Tests show that we can remove the recursive case with no impact - // on refworkload 0.83. If we need to reduce the size of the code - // emitted by compiler_lock_object() the recursive case is perfect - // candidate. - // - // A more extreme idea is to always inflate on stack-lock recursion. - // This lets us eliminate the recursive checks in compiler_lock_object - // and compiler_unlock_object and the (box->dhw == 0) encoding. - // A brief experiment - requiring changes to synchronizer.cpp, interpreter, - // and showed a performance *increase*. In the same experiment I eliminated - // the fast-path stack-lock code from the interpreter and always passed - // control to the "slow" operators in synchronizer.cpp. - - // RScratch contains the fetched obj->mark value from the failed CAS. - sub(Rscratch, STACK_BIAS, Rscratch); - sub(Rscratch, SP, Rscratch); - assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - andcc(Rscratch, 0xfffff003, Rscratch); - if (counters != NULL) { - // Accounting needs the Rscratch register - st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes()); - cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch); - ba_short(done); - } else { - ba(done); - delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes()); - } - - bind (IsInflated); - - // Try to CAS m->owner from null to Self - // Invariant: if we acquire the lock then _recursions should be 0. - add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); - mov(G2_thread, Rscratch); - cas_ptr(Rmark, G0, Rscratch); - andcc(Rscratch, Rscratch, G0); // set ICCs for done: icc.zf iff success - // set icc.zf : 1=success 0=failure - // ST box->displaced_header = NonZero. - // Any non-zero value suffices: - // markWord::unused_mark(), G2_thread, RBox, RScratch, rsp, etc. - st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes()); - // Intentional fall-through into done - - bind (done); -} - -void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark, - Register Rbox, Register Rscratch, - bool try_bias) { - Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); - - Label done ; - - // Beware ... If the aggregate size of the code emitted by CLO and CUO is - // is too large performance rolls abruptly off a cliff. - // This could be related to inlining policies, code cache management, or - // I$ effects. - Label LStacked ; - - if (try_bias) { - // TODO: eliminate redundant LDs of obj->mark - biased_locking_exit(mark_addr, Rscratch, done); - } - - ld_ptr(Roop, oopDesc::mark_offset_in_bytes(), Rmark); - ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rscratch); - andcc(Rscratch, Rscratch, G0); - brx(Assembler::zero, false, Assembler::pn, done); - delayed()->nop(); // consider: relocate fetch of mark, above, into this DS - andcc(Rmark, 2, G0); - brx(Assembler::zero, false, Assembler::pt, LStacked); - delayed()->nop(); - - // It's inflated - // Conceptually we need a #loadstore|#storestore "release" MEMBAR before - // the ST of 0 into _owner which releases the lock. This prevents loads - // and stores within the critical section from reordering (floating) - // past the store that releases the lock. But TSO is a strong memory model - // and that particular flavor of barrier is a noop, so we can safely elide it. - // Note that we use 1-0 locking by default for the inflated case. We - // close the resultant (and rare) race by having contended threads in - // monitorenter periodically poll _owner. - - // 1-0 form : avoids CAS and MEMBAR in the common case - // Do not bother to ratify that m->Owner == Self. - ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox); - orcc(Rbox, G0, G0); - brx(Assembler::notZero, false, Assembler::pn, done); - delayed()-> - ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch); - ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox); - orcc(Rbox, Rscratch, G0); - brx(Assembler::zero, false, Assembler::pt, done); - delayed()-> - st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - - membar(StoreLoad); - // Check that _succ is (or remains) non-zero - ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch); - andcc(Rscratch, Rscratch, G0); - brx(Assembler::notZero, false, Assembler::pt, done); - delayed()->andcc(G0, G0, G0); - add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); - mov(G2_thread, Rscratch); - cas_ptr(Rmark, G0, Rscratch); - cmp(Rscratch, G0); - // invert icc.zf and goto done - // A slightly better v8+/v9 idiom would be the following: - // movrnz Rscratch,1,Rscratch - // ba done - // xorcc Rscratch,1,G0 - // In v8+ mode the idiom would be valid IFF Rscratch was a G or O register - brx(Assembler::notZero, false, Assembler::pt, done); - delayed()->cmp(G0, G0); - br(Assembler::always, false, Assembler::pt, done); - delayed()->cmp(G0, 1); - - bind (LStacked); - // Consider: we could replace the expensive CAS in the exit - // path with a simple ST of the displaced mark value fetched from - // the on-stack basiclock box. That admits a race where a thread T2 - // in the slow lock path -- inflating with monitor M -- could race a - // thread T1 in the fast unlock path, resulting in a missed wakeup for T2. - // More precisely T1 in the stack-lock unlock path could "stomp" the - // inflated mark value M installed by T2, resulting in an orphan - // object monitor M and T2 becoming stranded. We can remedy that situation - // by having T2 periodically poll the object's mark word using timed wait - // operations. If T2 discovers that a stomp has occurred it vacates - // the monitor M and wakes any other threads stranded on the now-orphan M. - // In addition the monitor scavenger, which performs deflation, - // would also need to check for orpan monitors and stranded threads. - // - // Finally, inflation is also used when T2 needs to assign a hashCode - // to O and O is stack-locked by T1. The "stomp" race could cause - // an assigned hashCode value to be lost. We can avoid that condition - // and provide the necessary hashCode stability invariants by ensuring - // that hashCode generation is idempotent between copying GCs. - // For example we could compute the hashCode of an object O as - // O's heap address XOR some high quality RNG value that is refreshed - // at GC-time. The monitor scavenger would install the hashCode - // found in any orphan monitors. Again, the mechanism admits a - // lost-update "stomp" WAW race but detects and recovers as needed. - // - // A prototype implementation showed excellent results, although - // the scavenger and timeout code was rather involved. - - cas_ptr(mark_addr.base(), Rbox, Rscratch); - cmp(Rbox, Rscratch); - // Intentional fall through into done ... - - bind(done); -} - -void MacroAssembler::verify_tlab() { -#ifdef ASSERT - if (UseTLAB && VerifyOops) { - Label next, next2, ok; - Register t1 = L0; - Register t2 = L1; - Register t3 = L2; - - save_frame(0); - ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1); - ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t2); - or3(t1, t2, t3); - cmp_and_br_short(t1, t2, Assembler::greaterEqual, Assembler::pn, next); - STOP("assert(top >= start)"); - should_not_reach_here(); - - bind(next); - ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1); - ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), t2); - or3(t3, t2, t3); - cmp_and_br_short(t1, t2, Assembler::lessEqual, Assembler::pn, next2); - STOP("assert(top <= end)"); - should_not_reach_here(); - - bind(next2); - and3(t3, MinObjAlignmentInBytesMask, t3); - cmp_and_br_short(t3, 0, Assembler::lessEqual, Assembler::pn, ok); - STOP("assert(aligned)"); - should_not_reach_here(); - - bind(ok); - restore(); - } -#endif -} - - -void MacroAssembler::eden_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 -){ - // make sure arguments make sense - assert_different_registers(obj, var_size_in_bytes, t1, t2); - assert(0 <= con_size_in_bytes && Assembler::is_simm13(con_size_in_bytes), "illegal object size"); - assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment"); - - if (!Universe::heap()->supports_inline_contig_alloc()) { - // No allocation in the shared eden. - ba(slow_case); - delayed()->nop(); - } else { - // get eden boundaries - // note: we need both top & top_addr! - const Register top_addr = t1; - const Register end = t2; - - CollectedHeap* ch = Universe::heap(); - set((intx)ch->top_addr(), top_addr); - intx delta = (intx)ch->end_addr() - (intx)ch->top_addr(); - ld_ptr(top_addr, delta, end); - ld_ptr(top_addr, 0, obj); - - // try to allocate - Label retry; - bind(retry); -#ifdef ASSERT - // make sure eden top is properly aligned - { - Label L; - btst(MinObjAlignmentInBytesMask, obj); - br(Assembler::zero, false, Assembler::pt, L); - delayed()->nop(); - STOP("eden top is not properly aligned"); - bind(L); - } -#endif // ASSERT - const Register free = end; - sub(end, obj, free); // compute amount of free space - if (var_size_in_bytes->is_valid()) { - // size is unknown at compile time - cmp(free, var_size_in_bytes); - brx(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case - delayed()->add(obj, var_size_in_bytes, end); - } else { - // size is known at compile time - cmp(free, con_size_in_bytes); - brx(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case - delayed()->add(obj, con_size_in_bytes, end); - } - // Compare obj with the value at top_addr; if still equal, swap the value of - // end with the value at top_addr. If not equal, read the value at top_addr - // into end. - cas_ptr(top_addr, obj, end); - // if someone beat us on the allocation, try again, otherwise continue - cmp(obj, end); - brx(Assembler::notEqual, false, Assembler::pn, retry); - delayed()->mov(end, obj); // nop if successfull since obj == end - -#ifdef ASSERT - // make sure eden top is properly aligned - { - Label L; - const Register top_addr = t1; - - set((intx)ch->top_addr(), top_addr); - ld_ptr(top_addr, 0, top_addr); - btst(MinObjAlignmentInBytesMask, top_addr); - br(Assembler::zero, false, Assembler::pt, L); - delayed()->nop(); - STOP("eden top is not properly aligned"); - bind(L); - } -#endif // ASSERT - } -} - - -void MacroAssembler::tlab_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 - Label& slow_case // continuation point if fast allocation fails -){ - // make sure arguments make sense - assert_different_registers(obj, var_size_in_bytes, t1); - assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size"); - assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment"); - - const Register free = t1; - - verify_tlab(); - - ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), obj); - - // calculate amount of free space - ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), free); - sub(free, obj, free); - - Label done; - if (var_size_in_bytes == noreg) { - cmp(free, con_size_in_bytes); - } else { - cmp(free, var_size_in_bytes); - } - br(Assembler::less, false, Assembler::pn, slow_case); - // calculate the new top pointer - if (var_size_in_bytes == noreg) { - delayed()->add(obj, con_size_in_bytes, free); - } else { - delayed()->add(obj, var_size_in_bytes, free); - } - - bind(done); - -#ifdef ASSERT - // make sure new free pointer is properly aligned - { - Label L; - btst(MinObjAlignmentInBytesMask, free); - br(Assembler::zero, false, Assembler::pt, L); - delayed()->nop(); - STOP("updated TLAB free is not properly aligned"); - bind(L); - } -#endif // ASSERT - - // update the tlab top pointer - st_ptr(free, G2_thread, in_bytes(JavaThread::tlab_top_offset())); - verify_tlab(); -} - -void MacroAssembler::zero_memory(Register base, Register index) { - assert_different_registers(base, index); - Label loop; - bind(loop); - subcc(index, HeapWordSize, index); - brx(Assembler::greaterEqual, true, Assembler::pt, loop); - delayed()->st_ptr(G0, base, index); -} - -void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, - Register t1, Register t2) { - // Bump total bytes allocated by this thread - assert(t1->is_global(), "must be global reg"); // so all 64 bits are saved on a context switch - assert_different_registers(size_in_bytes.register_or_noreg(), t1, t2); - // v8 support has gone the way of the dodo - ldx(G2_thread, in_bytes(JavaThread::allocated_bytes_offset()), t1); - add(t1, ensure_simm13_or_reg(size_in_bytes, t2), t1); - stx(t1, G2_thread, in_bytes(JavaThread::allocated_bytes_offset())); -} - -Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) { - switch (cond) { - // Note some conditions are synonyms for others - case Assembler::never: return Assembler::always; - case Assembler::zero: return Assembler::notZero; - case Assembler::lessEqual: return Assembler::greater; - case Assembler::less: return Assembler::greaterEqual; - case Assembler::lessEqualUnsigned: return Assembler::greaterUnsigned; - case Assembler::lessUnsigned: return Assembler::greaterEqualUnsigned; - case Assembler::negative: return Assembler::positive; - case Assembler::overflowSet: return Assembler::overflowClear; - case Assembler::always: return Assembler::never; - case Assembler::notZero: return Assembler::zero; - case Assembler::greater: return Assembler::lessEqual; - case Assembler::greaterEqual: return Assembler::less; - case Assembler::greaterUnsigned: return Assembler::lessEqualUnsigned; - case Assembler::greaterEqualUnsigned: return Assembler::lessUnsigned; - case Assembler::positive: return Assembler::negative; - case Assembler::overflowClear: return Assembler::overflowSet; - } - - ShouldNotReachHere(); return Assembler::overflowClear; -} - -void MacroAssembler::cond_inc(Assembler::Condition cond, address counter_ptr, - Register Rtmp1, Register Rtmp2 /*, Register Rtmp3, Register Rtmp4 */) { - Condition negated_cond = negate_condition(cond); - Label L; - brx(negated_cond, false, Assembler::pt, L); - delayed()->nop(); - inc_counter(counter_ptr, Rtmp1, Rtmp2); - bind(L); -} - -void MacroAssembler::inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2) { - AddressLiteral addrlit(counter_addr); - sethi(addrlit, Rtmp1); // Move hi22 bits into temporary register. - Address addr(Rtmp1, addrlit.low10()); // Build an address with low10 bits. - ld(addr, Rtmp2); - inc(Rtmp2); - st(Rtmp2, addr); -} - -void MacroAssembler::inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2) { - inc_counter((address) counter_addr, Rtmp1, Rtmp2); -} - -SkipIfEqual::SkipIfEqual( - MacroAssembler* masm, Register temp, const bool* flag_addr, - Assembler::Condition condition) { - _masm = masm; - AddressLiteral flag(flag_addr); - _masm->sethi(flag, temp); - _masm->ldub(temp, flag.low10(), temp); - _masm->tst(temp); - _masm->br(condition, false, Assembler::pt, _label); - _masm->delayed()->nop(); -} - -SkipIfEqual::~SkipIfEqual() { - _masm->bind(_label); -} - -void MacroAssembler::bang_stack_with_offset(int offset) { - // stack grows down, caller passes positive offset - assert(offset > 0, "must bang with negative offset"); - set((-offset)+STACK_BIAS, G3_scratch); - st(G0, SP, G3_scratch); -} - -// Writes to stack successive pages until offset reached to check for -// stack overflow + shadow pages. This clobbers tsp and scratch. -void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp, - Register Rscratch) { - // Use stack pointer in temp stack pointer - mov(SP, Rtsp); - - // Bang stack for total size given plus stack shadow page size. - // Bang one page at a time because a large size can overflow yellow and - // red zones (the bang will fail but stack overflow handling can't tell that - // it was a stack overflow bang vs a regular segv). - int offset = os::vm_page_size(); - Register Roffset = Rscratch; - - Label loop; - bind(loop); - set((-offset)+STACK_BIAS, Rscratch); - st(G0, Rtsp, Rscratch); - set(offset, Roffset); - sub(Rsize, Roffset, Rsize); - cmp(Rsize, G0); - br(Assembler::greater, false, Assembler::pn, loop); - delayed()->sub(Rtsp, Roffset, Rtsp); - - // Bang down shadow pages too. - // At this point, (tmp-0) is the last address touched, so don't - // touch it again. (It was touched as (tmp-pagesize) but then tmp - // was post-decremented.) Skip this address by starting at i=1, and - // touch a few more pages below. N.B. It is important to touch all - // the way down to and including i=StackShadowPages. - for (int i = 1; i < JavaThread::stack_shadow_zone_size() / os::vm_page_size(); i++) { - set((-i*offset)+STACK_BIAS, Rscratch); - st(G0, Rtsp, Rscratch); - } -} - -void MacroAssembler::reserved_stack_check() { - // testing if reserved zone needs to be enabled - Label no_reserved_zone_enabling; - - ld_ptr(G2_thread, JavaThread::reserved_stack_activation_offset(), G4_scratch); - cmp_and_brx_short(SP, G4_scratch, Assembler::lessUnsigned, Assembler::pt, no_reserved_zone_enabling); - - call_VM_leaf(L0, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), G2_thread); - - AddressLiteral stub(StubRoutines::throw_delayed_StackOverflowError_entry()); - jump_to(stub, G4_scratch); - delayed()->restore(); - - should_not_reach_here(); - - bind(no_reserved_zone_enabling); -} -// ((OopHandle)result).resolve(); -void MacroAssembler::resolve_oop_handle(Register result, Register tmp) { - // OopHandle::resolve is an indirection. - access_load_at(T_OBJECT, IN_NATIVE, Address(result, 0), result, tmp); -} - -void MacroAssembler::load_mirror(Register mirror, Register method, Register tmp) { - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - ld_ptr(method, in_bytes(Method::const_offset()), mirror); - ld_ptr(mirror, in_bytes(ConstMethod::constants_offset()), mirror); - ld_ptr(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror); - ld_ptr(mirror, mirror_offset, mirror); - resolve_oop_handle(mirror, tmp); -} - -void MacroAssembler::load_klass(Register src_oop, Register klass) { - // The number of bytes in this code is used by - // MachCallDynamicJavaNode::ret_addr_offset() - // if this changes, change that. - if (UseCompressedClassPointers) { - lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass); - decode_klass_not_null(klass); - } else { - ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass); - } -} - -void MacroAssembler::store_klass(Register klass, Register dst_oop) { - if (UseCompressedClassPointers) { - assert(dst_oop != klass, "not enough registers"); - encode_klass_not_null(klass); - st(klass, dst_oop, oopDesc::klass_offset_in_bytes()); - } else { - st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes()); - } -} - -void MacroAssembler::store_klass_gap(Register s, Register d) { - if (UseCompressedClassPointers) { - assert(s != d, "not enough registers"); - st(s, d, oopDesc::klass_gap_offset_in_bytes()); - } -} - -void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, - Register src, Address dst, Register tmp) { - BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - decorators = AccessInternal::decorator_fixup(decorators); - bool as_raw = (decorators & AS_RAW) != 0; - if (as_raw) { - bs->BarrierSetAssembler::store_at(this, decorators, type, src, dst, tmp); - } else { - bs->store_at(this, decorators, type, src, dst, tmp); - } -} - -void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, - Address src, Register dst, Register tmp) { - BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); - decorators = AccessInternal::decorator_fixup(decorators); - bool as_raw = (decorators & AS_RAW) != 0; - if (as_raw) { - bs->BarrierSetAssembler::load_at(this, decorators, type, src, dst, tmp); - } else { - bs->load_at(this, decorators, type, src, dst, tmp); - } -} - -void MacroAssembler::load_heap_oop(const Address& s, Register d, Register tmp, DecoratorSet decorators) { - access_load_at(T_OBJECT, IN_HEAP | decorators, s, d, tmp); -} - -void MacroAssembler::load_heap_oop(Register s1, Register s2, Register d, Register tmp, DecoratorSet decorators) { - access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2), d, tmp); -} - -void MacroAssembler::load_heap_oop(Register s1, int simm13a, Register d, Register tmp, DecoratorSet decorators) { - access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, simm13a), d, tmp); -} - -void MacroAssembler::load_heap_oop(Register s1, RegisterOrConstant s2, Register d, Register tmp, DecoratorSet decorators) { - if (s2.is_constant()) { - access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2.as_constant()), d, tmp); - } else { - access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2.as_register()), d, tmp); - } -} - -void MacroAssembler::store_heap_oop(Register d, Register s1, Register s2, Register tmp, DecoratorSet decorators) { - access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(s1, s2), tmp); -} - -void MacroAssembler::store_heap_oop(Register d, Register s1, int simm13a, Register tmp, DecoratorSet decorators) { - access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(s1, simm13a), tmp); -} - -void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset, Register tmp, DecoratorSet decorators) { - if (a.has_index()) { - assert(!a.has_disp(), "not supported yet"); - assert(offset == 0, "not supported yet"); - access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(a.base(), a.index()), tmp); - } else { - access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(a.base(), a.disp() + offset), tmp); - } -} - - -void MacroAssembler::encode_heap_oop(Register src, Register dst) { - assert (UseCompressedOops, "must be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); - assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); - verify_oop(src); - if (CompressedOops::base() == NULL) { - srlx(src, LogMinObjAlignmentInBytes, dst); - return; - } - Label done; - if (src == dst) { - // optimize for frequent case src == dst - bpr(rc_nz, true, Assembler::pt, src, done); - delayed() -> sub(src, G6_heapbase, dst); // annuled if not taken - bind(done); - srlx(src, LogMinObjAlignmentInBytes, dst); - } else { - bpr(rc_z, false, Assembler::pn, src, done); - delayed() -> mov(G0, dst); - // could be moved before branch, and annulate delay, - // but may add some unneeded work decoding null - sub(src, G6_heapbase, dst); - srlx(dst, LogMinObjAlignmentInBytes, dst); - bind(done); - } -} - - -void MacroAssembler::encode_heap_oop_not_null(Register r) { - assert (UseCompressedOops, "must be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); - assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); - verify_oop(r); - if (CompressedOops::base() != NULL) - sub(r, G6_heapbase, r); - srlx(r, LogMinObjAlignmentInBytes, r); -} - -void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) { - assert (UseCompressedOops, "must be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); - assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); - verify_oop(src); - if (CompressedOops::base() == NULL) { - srlx(src, LogMinObjAlignmentInBytes, dst); - } else { - sub(src, G6_heapbase, dst); - srlx(dst, LogMinObjAlignmentInBytes, dst); - } -} - -// Same algorithm as oops.inline.hpp decode_heap_oop. -void MacroAssembler::decode_heap_oop(Register src, Register dst) { - assert (UseCompressedOops, "must be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); - assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); - sllx(src, LogMinObjAlignmentInBytes, dst); - if (CompressedOops::base() != NULL) { - Label done; - bpr(rc_nz, true, Assembler::pt, dst, done); - delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken - bind(done); - } - verify_oop(dst); -} - -void MacroAssembler::decode_heap_oop_not_null(Register r) { - // Do not add assert code to this unless you change vtableStubs_sparc.cpp - // pd_code_size_limit. - // Also do not verify_oop as this is called by verify_oop. - assert (UseCompressedOops, "must be compressed"); - assert (Universe::heap() != NULL, "java heap should be initialized"); - assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); - sllx(r, LogMinObjAlignmentInBytes, r); - if (CompressedOops::base() != NULL) - add(r, G6_heapbase, r); -} - -void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { - // Do not add assert code to this unless you change vtableStubs_sparc.cpp - // pd_code_size_limit. - // Also do not verify_oop as this is called by verify_oop. - assert (UseCompressedOops, "must be compressed"); - assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); - sllx(src, LogMinObjAlignmentInBytes, dst); - if (CompressedOops::base() != NULL) - add(dst, G6_heapbase, dst); -} - -void MacroAssembler::encode_klass_not_null(Register r) { - assert (UseCompressedClassPointers, "must be compressed"); - if (CompressedKlassPointers::base() != NULL) { - assert(r != G6_heapbase, "bad register choice"); - set((intptr_t)CompressedKlassPointers::base(), G6_heapbase); - sub(r, G6_heapbase, r); - if (CompressedKlassPointers::shift() != 0) { - assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift(), "decode alg wrong"); - srlx(r, LogKlassAlignmentInBytes, r); - } - reinit_heapbase(); - } else { - assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong"); - srlx(r, CompressedKlassPointers::shift(), r); - } -} - -void MacroAssembler::encode_klass_not_null(Register src, Register dst) { - if (src == dst) { - encode_klass_not_null(src); - } else { - assert (UseCompressedClassPointers, "must be compressed"); - if (CompressedKlassPointers::base() != NULL) { - set((intptr_t)CompressedKlassPointers::base(), dst); - sub(src, dst, dst); - if (CompressedKlassPointers::shift() != 0) { - srlx(dst, LogKlassAlignmentInBytes, dst); - } - } else { - // shift src into dst - assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong"); - srlx(src, CompressedKlassPointers::shift(), dst); - } - } -} - -// Function instr_size_for_decode_klass_not_null() counts the instructions -// generated by decode_klass_not_null() and reinit_heapbase(). Hence, if -// the instructions they generate change, then this method needs to be updated. -int MacroAssembler::instr_size_for_decode_klass_not_null() { - assert (UseCompressedClassPointers, "only for compressed klass ptrs"); - int num_instrs = 1; // shift src,dst or add - if (CompressedKlassPointers::base() != NULL) { - // set + add + set - num_instrs += insts_for_internal_set((intptr_t)CompressedKlassPointers::base()) + - insts_for_internal_set((intptr_t)CompressedOops::ptrs_base()); - if (CompressedKlassPointers::shift() != 0) { - num_instrs += 1; // sllx - } - } - return num_instrs * BytesPerInstWord; -} - -// !!! If the instructions that get generated here change then function -// instr_size_for_decode_klass_not_null() needs to get updated. -void MacroAssembler::decode_klass_not_null(Register r) { - // Do not add assert code to this unless you change vtableStubs_sparc.cpp - // pd_code_size_limit. - assert (UseCompressedClassPointers, "must be compressed"); - if (CompressedKlassPointers::base() != NULL) { - assert(r != G6_heapbase, "bad register choice"); - set((intptr_t)CompressedKlassPointers::base(), G6_heapbase); - if (CompressedKlassPointers::shift() != 0) - sllx(r, LogKlassAlignmentInBytes, r); - add(r, G6_heapbase, r); - reinit_heapbase(); - } else { - assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong"); - sllx(r, CompressedKlassPointers::shift(), r); - } -} - -void MacroAssembler::decode_klass_not_null(Register src, Register dst) { - if (src == dst) { - decode_klass_not_null(src); - } else { - // Do not add assert code to this unless you change vtableStubs_sparc.cpp - // pd_code_size_limit. - assert (UseCompressedClassPointers, "must be compressed"); - if (CompressedKlassPointers::base() != NULL) { - if (CompressedKlassPointers::shift() != 0) { - assert((src != G6_heapbase) && (dst != G6_heapbase), "bad register choice"); - set((intptr_t)CompressedKlassPointers::base(), G6_heapbase); - sllx(src, LogKlassAlignmentInBytes, dst); - add(dst, G6_heapbase, dst); - reinit_heapbase(); - } else { - set((intptr_t)CompressedKlassPointers::base(), dst); - add(src, dst, dst); - } - } else { - // shift/mov src into dst. - assert (LogKlassAlignmentInBytes == CompressedKlassPointers::shift() || CompressedKlassPointers::shift() == 0, "decode alg wrong"); - sllx(src, CompressedKlassPointers::shift(), dst); - } - } -} - -void MacroAssembler::reinit_heapbase() { - if (UseCompressedOops || UseCompressedClassPointers) { - if (Universe::heap() != NULL) { - set((intptr_t)CompressedOops::ptrs_base(), G6_heapbase); - } else { - AddressLiteral base(CompressedOops::ptrs_base_addr()); - load_ptr_contents(base, G6_heapbase); - } - } -} - -// Use BIS for zeroing (count is in bytes). -void MacroAssembler::bis_zeroing(Register to, Register count, Register temp, Label& Ldone) { - assert(UseBlockZeroing && VM_Version::has_blk_zeroing(), "only works with BIS zeroing"); - Register end = count; - int cache_line_size = VM_Version::prefetch_data_size(); - assert(cache_line_size > 0, "cache line size should be known for this code"); - // Minimum count when BIS zeroing can be used since - // it needs membar which is expensive. - int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit); - - Label small_loop; - // Check if count is negative (dead code) or zero. - // Note, count uses 64bit in 64 bit VM. - cmp_and_brx_short(count, 0, Assembler::lessEqual, Assembler::pn, Ldone); - - // Use BIS zeroing only for big arrays since it requires membar. - if (Assembler::is_simm13(block_zero_size)) { // < 4096 - cmp(count, block_zero_size); - } else { - set(block_zero_size, temp); - cmp(count, temp); - } - br(Assembler::lessUnsigned, false, Assembler::pt, small_loop); - delayed()->add(to, count, end); - - // Note: size is >= three (32 bytes) cache lines. - - // Clean the beginning of space up to next cache line. - for (int offs = 0; offs < cache_line_size; offs += 8) { - stx(G0, to, offs); - } - - // align to next cache line - add(to, cache_line_size, to); - and3(to, -cache_line_size, to); - - // Note: size left >= two (32 bytes) cache lines. - - // BIS should not be used to zero tail (64 bytes) - // to avoid zeroing a header of the following object. - sub(end, (cache_line_size*2)-8, end); - - Label bis_loop; - bind(bis_loop); - stxa(G0, to, G0, Assembler::ASI_ST_BLKINIT_PRIMARY); - add(to, cache_line_size, to); - cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, bis_loop); - - // BIS needs membar. - membar(Assembler::StoreLoad); - - add(end, (cache_line_size*2)-8, end); // restore end - cmp_and_brx_short(to, end, Assembler::greaterEqualUnsigned, Assembler::pn, Ldone); - - // Clean the tail. - bind(small_loop); - stx(G0, to, 0); - add(to, 8, to); - cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, small_loop); - nop(); // Separate short branches -} - -/** - * Update CRC-32[C] with a byte value according to constants in table - * - * @param [in,out]crc Register containing the crc. - * @param [in]val Register containing the byte to fold into the CRC. - * @param [in]table Register containing the table of crc constants. - * - * uint32_t crc; - * val = crc_table[(val ^ crc) & 0xFF]; - * crc = val ^ (crc >> 8); - */ -void MacroAssembler::update_byte_crc32(Register crc, Register val, Register table) { - xor3(val, crc, val); - and3(val, 0xFF, val); - sllx(val, 2, val); - lduw(table, val, val); - srlx(crc, 8, crc); - xor3(val, crc, crc); -} - -// Reverse byte order of lower 32 bits, assuming upper 32 bits all zeros -void MacroAssembler::reverse_bytes_32(Register src, Register dst, Register tmp) { - srlx(src, 24, dst); - - sllx(src, 32+8, tmp); - srlx(tmp, 32+24, tmp); - sllx(tmp, 8, tmp); - or3(dst, tmp, dst); - - sllx(src, 32+16, tmp); - srlx(tmp, 32+24, tmp); - sllx(tmp, 16, tmp); - or3(dst, tmp, dst); - - sllx(src, 32+24, tmp); - srlx(tmp, 32, tmp); - or3(dst, tmp, dst); -} - -void MacroAssembler::movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2) { - reverse_bytes_32(src, tmp1, tmp2); - movxtod(tmp1, dst); -} - -void MacroAssembler::movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2) { - movdtox(src, tmp1); - reverse_bytes_32(tmp1, dst, tmp2); -} - -void MacroAssembler::fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register buf, int offset) { - xmulx(xcrc_hi, xK_hi, xtmp_lo); - xmulxhi(xcrc_hi, xK_hi, xtmp_hi); - xmulxhi(xcrc_lo, xK_lo, xcrc_hi); - xmulx(xcrc_lo, xK_lo, xcrc_lo); - xor3(xcrc_lo, xtmp_lo, xcrc_lo); - xor3(xcrc_hi, xtmp_hi, xcrc_hi); - ldxl(buf, G0, xtmp_lo); - inc(buf, 8); - ldxl(buf, G0, xtmp_hi); - inc(buf, 8); - xor3(xcrc_lo, xtmp_lo, xcrc_lo); - xor3(xcrc_hi, xtmp_hi, xcrc_hi); -} - -void MacroAssembler::fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register xbuf_hi, Register xbuf_lo) { - mov(xcrc_lo, xtmp_lo); - mov(xcrc_hi, xtmp_hi); - xmulx(xtmp_hi, xK_hi, xtmp_lo); - xmulxhi(xtmp_hi, xK_hi, xtmp_hi); - xmulxhi(xcrc_lo, xK_lo, xcrc_hi); - xmulx(xcrc_lo, xK_lo, xcrc_lo); - xor3(xcrc_lo, xbuf_lo, xcrc_lo); - xor3(xcrc_hi, xbuf_hi, xcrc_hi); - xor3(xcrc_lo, xtmp_lo, xcrc_lo); - xor3(xcrc_hi, xtmp_hi, xcrc_hi); -} - -void MacroAssembler::fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp) { - and3(xcrc, 0xFF, tmp); - sllx(tmp, 2, tmp); - lduw(table, tmp, xtmp); - srlx(xcrc, 8, xcrc); - xor3(xtmp, xcrc, xcrc); -} - -void MacroAssembler::fold_8bit_crc32(Register crc, Register table, Register tmp) { - and3(crc, 0xFF, tmp); - srlx(crc, 8, crc); - sllx(tmp, 2, tmp); - lduw(table, tmp, tmp); - xor3(tmp, crc, crc); -} - -#define CRC32_TMP_REG_NUM 18 - -#define CRC32_CONST_64 0x163cd6124 -#define CRC32_CONST_96 0x0ccaa009e -#define CRC32_CONST_160 0x1751997d0 -#define CRC32_CONST_480 0x1c6e41596 -#define CRC32_CONST_544 0x154442bd4 - -void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Register table) { - - Label L_cleanup_loop, L_cleanup_check, L_align_loop, L_align_check; - Label L_main_loop_prologue; - Label L_fold_512b, L_fold_512b_loop, L_fold_128b; - Label L_fold_tail, L_fold_tail_loop; - Label L_8byte_fold_check; - - const Register tmp[CRC32_TMP_REG_NUM] = {L0, L1, L2, L3, L4, L5, L6, G1, I0, I1, I2, I3, I4, I5, I7, O4, O5, G3}; - - Register const_64 = tmp[CRC32_TMP_REG_NUM-1]; - Register const_96 = tmp[CRC32_TMP_REG_NUM-1]; - Register const_160 = tmp[CRC32_TMP_REG_NUM-2]; - Register const_480 = tmp[CRC32_TMP_REG_NUM-1]; - Register const_544 = tmp[CRC32_TMP_REG_NUM-2]; - - set(ExternalAddress(StubRoutines::crc_table_addr()), table); - - not1(crc); // ~c - clruwu(crc); // clear upper 32 bits of crc - - // Check if below cutoff, proceed directly to cleanup code - mov(31, G4); - cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_check); - - // Align buffer to 8 byte boundry - mov(8, O5); - and3(buf, 0x7, O4); - sub(O5, O4, O5); - and3(O5, 0x7, O5); - sub(len, O5, len); - ba(L_align_check); - delayed()->nop(); - - // Alignment loop, table look up method for up to 7 bytes - bind(L_align_loop); - ldub(buf, 0, O4); - inc(buf); - dec(O5); - xor3(O4, crc, O4); - and3(O4, 0xFF, O4); - sllx(O4, 2, O4); - lduw(table, O4, O4); - srlx(crc, 8, crc); - xor3(O4, crc, crc); - bind(L_align_check); - nop(); - cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_align_loop); - - // Aligned on 64-bit (8-byte) boundry at this point - // Check if still above cutoff (31-bytes) - mov(31, G4); - cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_check); - // At least 32 bytes left to process - - // Free up registers by storing them to FP registers - for (int i = 0; i < CRC32_TMP_REG_NUM; i++) { - movxtod(tmp[i], as_FloatRegister(2*i)); - } - - // Determine which loop to enter - // Shared prologue - ldxl(buf, G0, tmp[0]); - inc(buf, 8); - ldxl(buf, G0, tmp[1]); - inc(buf, 8); - xor3(tmp[0], crc, tmp[0]); // Fold CRC into first few bytes - and3(crc, 0, crc); // Clear out the crc register - // Main loop needs 128-bytes at least - mov(128, G4); - mov(64, tmp[2]); - cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_main_loop_prologue); - // Less than 64 bytes - nop(); - cmp_and_br_short(len, tmp[2], Assembler::lessUnsigned, Assembler::pt, L_fold_tail); - // Between 64 and 127 bytes - set64(CRC32_CONST_96, const_96, tmp[8]); - set64(CRC32_CONST_160, const_160, tmp[9]); - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[2], tmp[3], buf, 0); - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[4], tmp[5], buf, 16); - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[6], tmp[7], buf, 32); - dec(len, 48); - ba(L_fold_tail); - delayed()->nop(); - - bind(L_main_loop_prologue); - for (int i = 2; i < 8; i++) { - ldxl(buf, G0, tmp[i]); - inc(buf, 8); - } - - // Fold total 512 bits of polynomial on each iteration, - // 128 bits per each of 4 parallel streams - set64(CRC32_CONST_480, const_480, tmp[8]); - set64(CRC32_CONST_544, const_544, tmp[9]); - - mov(128, G4); - bind(L_fold_512b_loop); - fold_128bit_crc32(tmp[1], tmp[0], const_480, const_544, tmp[9], tmp[8], buf, 0); - fold_128bit_crc32(tmp[3], tmp[2], const_480, const_544, tmp[11], tmp[10], buf, 16); - fold_128bit_crc32(tmp[5], tmp[4], const_480, const_544, tmp[13], tmp[12], buf, 32); - fold_128bit_crc32(tmp[7], tmp[6], const_480, const_544, tmp[15], tmp[14], buf, 64); - dec(len, 64); - cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_fold_512b_loop); - - // Fold 512 bits to 128 bits - bind(L_fold_512b); - set64(CRC32_CONST_96, const_96, tmp[8]); - set64(CRC32_CONST_160, const_160, tmp[9]); - - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[3], tmp[2]); - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[5], tmp[4]); - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[8], tmp[9], tmp[7], tmp[6]); - dec(len, 48); - - // Fold the rest of 128 bits data chunks - bind(L_fold_tail); - mov(32, G4); - cmp_and_br_short(len, G4, Assembler::lessEqualUnsigned, Assembler::pt, L_fold_128b); - - set64(CRC32_CONST_96, const_96, tmp[8]); - set64(CRC32_CONST_160, const_160, tmp[9]); - - bind(L_fold_tail_loop); - fold_128bit_crc32(tmp[1], tmp[0], const_96, const_160, tmp[2], tmp[3], buf, 0); - sub(len, 16, len); - cmp_and_br_short(len, G4, Assembler::greaterEqualUnsigned, Assembler::pt, L_fold_tail_loop); - - // Fold the 128 bits in tmps 0 - 1 into tmp 1 - bind(L_fold_128b); - - set64(CRC32_CONST_64, const_64, tmp[4]); - - xmulx(const_64, tmp[0], tmp[2]); - xmulxhi(const_64, tmp[0], tmp[3]); - - srl(tmp[2], G0, tmp[4]); - xmulx(const_64, tmp[4], tmp[4]); - - srlx(tmp[2], 32, tmp[2]); - sllx(tmp[3], 32, tmp[3]); - or3(tmp[2], tmp[3], tmp[2]); - - xor3(tmp[4], tmp[1], tmp[4]); - xor3(tmp[4], tmp[2], tmp[1]); - dec(len, 8); - - // Use table lookup for the 8 bytes left in tmp[1] - dec(len, 8); - - // 8 8-bit folds to compute 32-bit CRC. - for (int j = 0; j < 4; j++) { - fold_8bit_crc32(tmp[1], table, tmp[2], tmp[3]); - } - srl(tmp[1], G0, crc); // move 32 bits to general register - for (int j = 0; j < 4; j++) { - fold_8bit_crc32(crc, table, tmp[3]); - } - - bind(L_8byte_fold_check); - - // Restore int registers saved in FP registers - for (int i = 0; i < CRC32_TMP_REG_NUM; i++) { - movdtox(as_FloatRegister(2*i), tmp[i]); - } - - ba(L_cleanup_check); - delayed()->nop(); - - // Table look-up method for the remaining few bytes - bind(L_cleanup_loop); - ldub(buf, 0, O4); - inc(buf); - dec(len); - xor3(O4, crc, O4); - and3(O4, 0xFF, O4); - sllx(O4, 2, O4); - lduw(table, O4, O4); - srlx(crc, 8, crc); - xor3(O4, crc, crc); - bind(L_cleanup_check); - nop(); - cmp_and_br_short(len, 0, Assembler::greaterUnsigned, Assembler::pt, L_cleanup_loop); - - not1(crc); -} - -#define CHUNK_LEN 128 /* 128 x 8B = 1KB */ -#define CHUNK_K1 0x1307a0206 /* reverseBits(pow(x, CHUNK_LEN*8*8*3 - 32) mod P(x)) << 1 */ -#define CHUNK_K2 0x1a0f717c4 /* reverseBits(pow(x, CHUNK_LEN*8*8*2 - 32) mod P(x)) << 1 */ -#define CHUNK_K3 0x0170076fa /* reverseBits(pow(x, CHUNK_LEN*8*8*1 - 32) mod P(x)) << 1 */ - -void MacroAssembler::kernel_crc32c(Register crc, Register buf, Register len, Register table) { - - Label L_crc32c_head, L_crc32c_aligned; - Label L_crc32c_parallel, L_crc32c_parallel_loop; - Label L_crc32c_serial, L_crc32c_x32_loop, L_crc32c_x8, L_crc32c_x8_loop; - Label L_crc32c_done, L_crc32c_tail, L_crc32c_return; - - set(ExternalAddress(StubRoutines::crc32c_table_addr()), table); - - cmp_and_br_short(len, 0, Assembler::lessEqual, Assembler::pn, L_crc32c_return); - - // clear upper 32 bits of crc - clruwu(crc); - - and3(buf, 7, G4); - cmp_and_brx_short(G4, 0, Assembler::equal, Assembler::pt, L_crc32c_aligned); - - mov(8, G1); - sub(G1, G4, G4); - - // ------ process the misaligned head (7 bytes or less) ------ - bind(L_crc32c_head); - - // crc = (crc >>> 8) ^ byteTable[(crc ^ b) & 0xFF]; - ldub(buf, 0, G1); - update_byte_crc32(crc, G1, table); - - inc(buf); - dec(len); - cmp_and_br_short(len, 0, Assembler::equal, Assembler::pn, L_crc32c_return); - dec(G4); - cmp_and_br_short(G4, 0, Assembler::greater, Assembler::pt, L_crc32c_head); - - // ------ process the 8-byte-aligned body ------ - bind(L_crc32c_aligned); - nop(); - cmp_and_br_short(len, 8, Assembler::less, Assembler::pn, L_crc32c_tail); - - // reverse the byte order of lower 32 bits to big endian, and move to FP side - movitof_revbytes(crc, F0, G1, G3); - - set(CHUNK_LEN*8*4, G4); - cmp_and_br_short(len, G4, Assembler::less, Assembler::pt, L_crc32c_serial); - - // ------ process four 1KB chunks in parallel ------ - bind(L_crc32c_parallel); - - fzero(FloatRegisterImpl::D, F2); - fzero(FloatRegisterImpl::D, F4); - fzero(FloatRegisterImpl::D, F6); - - mov(CHUNK_LEN - 1, G4); - bind(L_crc32c_parallel_loop); - // schedule ldf's ahead of crc32c's to hide the load-use latency - ldf(FloatRegisterImpl::D, buf, 0, F8); - ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*8, F10); - ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*16, F12); - ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*24, F14); - crc32c(F0, F8, F0); - crc32c(F2, F10, F2); - crc32c(F4, F12, F4); - crc32c(F6, F14, F6); - inc(buf, 8); - dec(G4); - cmp_and_br_short(G4, 0, Assembler::greater, Assembler::pt, L_crc32c_parallel_loop); - - ldf(FloatRegisterImpl::D, buf, 0, F8); - ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*8, F10); - ldf(FloatRegisterImpl::D, buf, CHUNK_LEN*16, F12); - crc32c(F0, F8, F0); - crc32c(F2, F10, F2); - crc32c(F4, F12, F4); - - inc(buf, CHUNK_LEN*24); - ldfl(FloatRegisterImpl::D, buf, G0, F14); // load in little endian - inc(buf, 8); - - prefetch(buf, 0, Assembler::severalReads); - prefetch(buf, CHUNK_LEN*8, Assembler::severalReads); - prefetch(buf, CHUNK_LEN*16, Assembler::severalReads); - prefetch(buf, CHUNK_LEN*24, Assembler::severalReads); - - // move to INT side, and reverse the byte order of lower 32 bits to little endian - movftoi_revbytes(F0, O4, G1, G4); - movftoi_revbytes(F2, O5, G1, G4); - movftoi_revbytes(F4, G5, G1, G4); - - // combine the results of 4 chunks - set64(CHUNK_K1, G3, G1); - xmulx(O4, G3, O4); - set64(CHUNK_K2, G3, G1); - xmulx(O5, G3, O5); - set64(CHUNK_K3, G3, G1); - xmulx(G5, G3, G5); - - movdtox(F14, G4); - xor3(O4, O5, O5); - xor3(G5, O5, O5); - xor3(G4, O5, O5); - - // reverse the byte order to big endian, via stack, and move to FP side - // TODO: use new revb instruction - add(SP, -8, G1); - srlx(G1, 3, G1); - sllx(G1, 3, G1); - stx(O5, G1, G0); - ldfl(FloatRegisterImpl::D, G1, G0, F2); // load in little endian - - crc32c(F6, F2, F0); - - set(CHUNK_LEN*8*4, G4); - sub(len, G4, len); - cmp_and_br_short(len, G4, Assembler::greaterEqual, Assembler::pt, L_crc32c_parallel); - nop(); - cmp_and_br_short(len, 0, Assembler::equal, Assembler::pt, L_crc32c_done); - - bind(L_crc32c_serial); - - mov(32, G4); - cmp_and_br_short(len, G4, Assembler::less, Assembler::pn, L_crc32c_x8); - - // ------ process 32B chunks ------ - bind(L_crc32c_x32_loop); - ldf(FloatRegisterImpl::D, buf, 0, F2); - crc32c(F0, F2, F0); - ldf(FloatRegisterImpl::D, buf, 8, F2); - crc32c(F0, F2, F0); - ldf(FloatRegisterImpl::D, buf, 16, F2); - crc32c(F0, F2, F0); - ldf(FloatRegisterImpl::D, buf, 24, F2); - inc(buf, 32); - crc32c(F0, F2, F0); - dec(len, 32); - cmp_and_br_short(len, G4, Assembler::greaterEqual, Assembler::pt, L_crc32c_x32_loop); - - bind(L_crc32c_x8); - nop(); - cmp_and_br_short(len, 8, Assembler::less, Assembler::pt, L_crc32c_done); - - // ------ process 8B chunks ------ - bind(L_crc32c_x8_loop); - ldf(FloatRegisterImpl::D, buf, 0, F2); - inc(buf, 8); - crc32c(F0, F2, F0); - dec(len, 8); - cmp_and_br_short(len, 8, Assembler::greaterEqual, Assembler::pt, L_crc32c_x8_loop); - - bind(L_crc32c_done); - - // move to INT side, and reverse the byte order of lower 32 bits to little endian - movftoi_revbytes(F0, crc, G1, G3); - - cmp_and_br_short(len, 0, Assembler::equal, Assembler::pt, L_crc32c_return); - - // ------ process the misaligned tail (7 bytes or less) ------ - bind(L_crc32c_tail); - - // crc = (crc >>> 8) ^ byteTable[(crc ^ b) & 0xFF]; - ldub(buf, 0, G1); - update_byte_crc32(crc, G1, table); - - inc(buf); - dec(len); - cmp_and_br_short(len, 0, Assembler::greater, Assembler::pt, L_crc32c_tail); - - bind(L_crc32c_return); - nop(); -} diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp +++ /dev/null @@ -1,1348 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_MACROASSEMBLER_SPARC_HPP -#define CPU_SPARC_MACROASSEMBLER_SPARC_HPP - -#include "asm/assembler.hpp" -#include "utilities/macros.hpp" - -// promises that the system will not use traps 16-31 -#define ST_RESERVED_FOR_USER_0 0x10 - -class BiasedLockingCounters; - - -// Register aliases for parts of the system: - -// 64 bit values can be kept in g1-g5, o1-o5 and o7 and all 64 bits are safe -// across context switches in V8+ ABI. Of course, there are no 64 bit regs -// in V8 ABI. All 64 bits are preserved in V9 ABI for all registers. - -// g2-g4 are scratch registers called "application globals". Their -// meaning is reserved to the "compilation system"--which means us! -// They are are not supposed to be touched by ordinary C code, although -// highly-optimized C code might steal them for temps. They are safe -// across thread switches, and the ABI requires that they be safe -// across function calls. -// -// g1 and g3 are touched by more modules. V8 allows g1 to be clobbered -// across func calls, and V8+ also allows g5 to be clobbered across -// func calls. Also, g1 and g5 can get touched while doing shared -// library loading. -// -// We must not touch g7 (it is the thread-self register) and g6 is -// reserved for certain tools. g0, of course, is always zero. -// -// (Sources: SunSoft Compilers Group, thread library engineers.) - -// %%%% The interpreter should be revisited to reduce global scratch regs. - -// This global always holds the current JavaThread pointer: - -REGISTER_DECLARATION(Register, G2_thread , G2); -REGISTER_DECLARATION(Register, G6_heapbase , G6); - -// The following globals are part of the Java calling convention: - -REGISTER_DECLARATION(Register, G5_method , G5); -REGISTER_DECLARATION(Register, G5_megamorphic_method , G5_method); -REGISTER_DECLARATION(Register, G5_inline_cache_reg , G5_method); - -// The following globals are used for the new C1 & interpreter calling convention: -REGISTER_DECLARATION(Register, Gargs , G4); // pointing to the last argument - -// This local is used to preserve G2_thread in the interpreter and in stubs: -REGISTER_DECLARATION(Register, L7_thread_cache , L7); - -// These globals are used as scratch registers in the interpreter: - -REGISTER_DECLARATION(Register, Gframe_size , G1); // SAME REG as G1_scratch -REGISTER_DECLARATION(Register, G1_scratch , G1); // also SAME -REGISTER_DECLARATION(Register, G3_scratch , G3); -REGISTER_DECLARATION(Register, G4_scratch , G4); - -// These globals are used as short-lived scratch registers in the compiler: - -REGISTER_DECLARATION(Register, Gtemp , G5); - -// JSR 292 fixed register usages: -REGISTER_DECLARATION(Register, G5_method_type , G5); -REGISTER_DECLARATION(Register, G3_method_handle , G3); -REGISTER_DECLARATION(Register, L7_mh_SP_save , L7); - -// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass, -// because a single patchable "set" instruction (NativeMovConstReg, -// or NativeMovConstPatching for compiler1) instruction -// serves to set up either quantity, depending on whether the compiled -// call site is an inline cache or is megamorphic. See the function -// CompiledIC::set_to_megamorphic. -// -// If a inline cache targets an interpreted method, then the -// G5 register will be used twice during the call. First, -// the call site will be patched to load a compiledICHolder -// into G5. (This is an ordered pair of ic_klass, method.) -// The c2i adapter will first check the ic_klass, then load -// G5_method with the method part of the pair just before -// jumping into the interpreter. -// -// Note that G5_method is only the method-self for the interpreter, -// and is logically unrelated to G5_megamorphic_method. -// -// Invariants on G2_thread (the JavaThread pointer): -// - it should not be used for any other purpose anywhere -// - it must be re-initialized by StubRoutines::call_stub() -// - it must be preserved around every use of call_VM - -// We can consider using g2/g3/g4 to cache more values than the -// JavaThread, such as the card-marking base or perhaps pointers into -// Eden. It's something of a waste to use them as scratch temporaries, -// since they are not supposed to be volatile. (Of course, if we find -// that Java doesn't benefit from application globals, then we can just -// use them as ordinary temporaries.) -// -// Since g1 and g5 (and/or g6) are the volatile (caller-save) registers, -// it makes sense to use them routinely for procedure linkage, -// whenever the On registers are not applicable. Examples: G5_method, -// G5_inline_cache_klass, and a double handful of miscellaneous compiler -// stubs. This means that compiler stubs, etc., should be kept to a -// maximum of two or three G-register arguments. - - -// stub frames - -REGISTER_DECLARATION(Register, Lentry_args , L0); // pointer to args passed to callee (interpreter) not stub itself - -// Interpreter frames - -REGISTER_DECLARATION(Register, Lesp , L0); // expression stack pointer -REGISTER_DECLARATION(Register, Lbcp , L1); // pointer to next bytecode -REGISTER_DECLARATION(Register, Lmethod , L2); -REGISTER_DECLARATION(Register, Llocals , L3); -REGISTER_DECLARATION(Register, Largs , L3); // pointer to locals for signature handler - // must match Llocals in asm interpreter -REGISTER_DECLARATION(Register, Lmonitors , L4); -REGISTER_DECLARATION(Register, Lbyte_code , L5); -// When calling out from the interpreter we record SP so that we can remove any extra stack -// space allocated during adapter transitions. This register is only live from the point -// of the call until we return. -REGISTER_DECLARATION(Register, Llast_SP , L5); -REGISTER_DECLARATION(Register, Lscratch , L5); -REGISTER_DECLARATION(Register, Lscratch2 , L6); -REGISTER_DECLARATION(Register, LcpoolCache , L6); // constant pool cache - -REGISTER_DECLARATION(Register, O5_savedSP , O5); -REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply - // a copy SP, so in 64-bit it's a biased value. The bias - // is added and removed as needed in the frame code. -REGISTER_DECLARATION(Register, IdispatchAddress , I3); // Register which saves the dispatch address for each bytecode -REGISTER_DECLARATION(Register, ImethodDataPtr , I2); // Pointer to the current method data - -// NOTE: Lscratch2 and LcpoolCache point to the same registers in -// the interpreter code. If Lscratch2 needs to be used for some -// purpose than LcpoolCache should be restore after that for -// the interpreter to work right -// (These assignments must be compatible with L7_thread_cache; see above.) - -// Lbcp points into the middle of the method object. - -// Exception processing -// These registers are passed into exception handlers. -// All exception handlers require the exception object being thrown. -// In addition, an nmethod's exception handler must be passed -// the address of the call site within the nmethod, to allow -// proper selection of the applicable catch block. -// (Interpreter frames use their own bcp() for this purpose.) -// -// The Oissuing_pc value is not always needed. When jumping to a -// handler that is known to be interpreted, the Oissuing_pc value can be -// omitted. An actual catch block in compiled code receives (from its -// nmethod's exception handler) the thrown exception in the Oexception, -// but it doesn't need the Oissuing_pc. -// -// If an exception handler (either interpreted or compiled) -// discovers there is no applicable catch block, it updates -// the Oissuing_pc to the continuation PC of its own caller, -// pops back to that caller's stack frame, and executes that -// caller's exception handler. Obviously, this process will -// iterate until the control stack is popped back to a method -// containing an applicable catch block. A key invariant is -// that the Oissuing_pc value is always a value local to -// the method whose exception handler is currently executing. -// -// Note: The issuing PC value is __not__ a raw return address (I7 value). -// It is a "return pc", the address __following__ the call. -// Raw return addresses are converted to issuing PCs by frame::pc(), -// or by stubs. Issuing PCs can be used directly with PC range tables. -// -REGISTER_DECLARATION(Register, Oexception , O0); // exception being thrown -REGISTER_DECLARATION(Register, Oissuing_pc , O1); // where the exception is coming from - -// Address is an abstraction used to represent a memory location. -// -// Note: A register location is represented via a Register, not -// via an address for efficiency & simplicity reasons. - -class Address { - private: - Register _base; // Base register. - RegisterOrConstant _index_or_disp; // Index register or constant displacement. - RelocationHolder _rspec; - - public: - Address() : _base(noreg), _index_or_disp(noreg) {} - - Address(Register base, RegisterOrConstant index_or_disp) - : _base(base), - _index_or_disp(index_or_disp) { - } - - Address(Register base, Register index) - : _base(base), - _index_or_disp(index) { - } - - Address(Register base, int disp) - : _base(base), - _index_or_disp(disp) { - } - -#ifdef ASSERT - // ByteSize is only a class when ASSERT is defined, otherwise it's an int. - Address(Register base, ByteSize disp) - : _base(base), - _index_or_disp(in_bytes(disp)) { - } -#endif - - // accessors - Register base() const { return _base; } - Register index() const { return _index_or_disp.as_register(); } - int disp() const { return _index_or_disp.as_constant(); } - - bool has_index() const { return _index_or_disp.is_register(); } - bool has_disp() const { return _index_or_disp.is_constant(); } - - bool uses(Register reg) const { return base() == reg || (has_index() && index() == reg); } - - const relocInfo::relocType rtype() { return _rspec.type(); } - const RelocationHolder& rspec() { return _rspec; } - - RelocationHolder rspec(int offset) const { - return offset == 0 ? _rspec : _rspec.plus(offset); - } - - inline bool is_simm13(int offset = 0); // check disp+offset for overflow - - Address plus_disp(int plusdisp) const { // bump disp by a small amount - assert(_index_or_disp.is_constant(), "must have a displacement"); - Address a(base(), disp() + plusdisp); - return a; - } - bool is_same_address(Address a) const { - // disregard _rspec - return base() == a.base() && (has_index() ? index() == a.index() : disp() == a.disp()); - } - - Address after_save() const { - Address a = (*this); - a._base = a._base->after_save(); - return a; - } - - Address after_restore() const { - Address a = (*this); - a._base = a._base->after_restore(); - return a; - } - - // Convert the raw encoding form into the form expected by the - // constructor for Address. - static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc); - - friend class Assembler; -}; - - -class AddressLiteral { - private: - address _address; - RelocationHolder _rspec; - - RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) { - switch (rtype) { - case relocInfo::external_word_type: - return external_word_Relocation::spec(addr); - case relocInfo::internal_word_type: - return internal_word_Relocation::spec(addr); - case relocInfo::opt_virtual_call_type: - return opt_virtual_call_Relocation::spec(); - case relocInfo::static_call_type: - return static_call_Relocation::spec(); - case relocInfo::runtime_call_type: - return runtime_call_Relocation::spec(); - case relocInfo::none: - return RelocationHolder(); - default: - ShouldNotReachHere(); - return RelocationHolder(); - } - } - - protected: - // creation - AddressLiteral() : _address(NULL), _rspec(NULL) {} - - public: - AddressLiteral(address addr, RelocationHolder const& rspec) - : _address(addr), - _rspec(rspec) {} - - // Some constructors to avoid casting at the call site. - AddressLiteral(jobject obj, RelocationHolder const& rspec) - : _address((address) obj), - _rspec(rspec) {} - - AddressLiteral(intptr_t value, RelocationHolder const& rspec) - : _address((address) value), - _rspec(rspec) {} - - AddressLiteral(address addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - // Some constructors to avoid casting at the call site. - AddressLiteral(address* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(bool* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(const bool* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(signed char* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(int* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(intptr_t addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - // 32-bit complains about a multiple declaration for int*. - AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(Metadata* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(Metadata** addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(float* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - AddressLiteral(double* addr, relocInfo::relocType rtype = relocInfo::none) - : _address((address) addr), - _rspec(rspec_from_rtype(rtype, (address) addr)) {} - - intptr_t value() const { return (intptr_t) _address; } - int low10() const; - - const relocInfo::relocType rtype() const { return _rspec.type(); } - const RelocationHolder& rspec() const { return _rspec; } - - RelocationHolder rspec(int offset) const { - return offset == 0 ? _rspec : _rspec.plus(offset); - } -}; - -// Convenience classes -class ExternalAddress: public AddressLiteral { - private: - static relocInfo::relocType reloc_for_target(address target) { - // Sometimes ExternalAddress is used for values which aren't - // exactly addresses, like the card table base. - // external_word_type can't be used for values in the first page - // so just skip the reloc in that case. - return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none; - } - - public: - ExternalAddress(address target) : AddressLiteral(target, reloc_for_target( target)) {} - ExternalAddress(Metadata** target) : AddressLiteral(target, reloc_for_target((address) target)) {} -}; - -inline Address RegisterImpl::address_in_saved_window() const { - return (Address(SP, (sp_offset_in_saved_window() * wordSize) + STACK_BIAS)); -} - - - -// Argument is an abstraction used to represent an outgoing -// actual argument or an incoming formal parameter, whether -// it resides in memory or in a register, in a manner consistent -// with the SPARC Application Binary Interface, or ABI. This is -// often referred to as the native or C calling convention. - -class Argument { - private: - int _number; - bool _is_in; - - public: - enum { - n_register_parameters = 6, // only 6 registers may contain integer parameters - n_float_register_parameters = 16 // Can have up to 16 floating registers - }; - - // creation - Argument(int number, bool is_in) : _number(number), _is_in(is_in) {} - - int number() const { return _number; } - bool is_in() const { return _is_in; } - bool is_out() const { return !is_in(); } - - Argument successor() const { return Argument(number() + 1, is_in()); } - Argument as_in() const { return Argument(number(), true ); } - Argument as_out() const { return Argument(number(), false); } - - // locating register-based arguments: - bool is_register() const { return _number < n_register_parameters; } - - // locating Floating Point register-based arguments: - bool is_float_register() const { return _number < n_float_register_parameters; } - - FloatRegister as_float_register() const { - assert(is_float_register(), "must be a register argument"); - return as_FloatRegister(( number() *2 ) + 1); - } - FloatRegister as_double_register() const { - assert(is_float_register(), "must be a register argument"); - return as_FloatRegister(( number() *2 )); - } - - Register as_register() const { - assert(is_register(), "must be a register argument"); - return is_in() ? as_iRegister(number()) : as_oRegister(number()); - } - - // locating memory-based arguments - Address as_address() const { - assert(!is_register(), "must be a memory argument"); - return address_in_frame(); - } - - // When applied to a register-based argument, give the corresponding address - // into the 6-word area "into which callee may store register arguments" - // (This is a different place than the corresponding register-save area location.) - Address address_in_frame() const; - - // debugging - const char* name() const; - - friend class Assembler; -}; - - -class RegistersForDebugging : public StackObj { - private: - static const RegistersForDebugging& _dummy; // not ODR-used so not defined - - public: - intptr_t i[8], l[8], o[8], g[8]; - float f[32]; - double d[32]; - - void print(outputStream* s); - - static int i_offset(int j) { return offset_of(RegistersForDebugging, i) + j * sizeof(_dummy.i[0]); } - static int l_offset(int j) { return offset_of(RegistersForDebugging, l) + j * sizeof(_dummy.l[0]); } - static int o_offset(int j) { return offset_of(RegistersForDebugging, o) + j * sizeof(_dummy.o[0]); } - static int g_offset(int j) { return offset_of(RegistersForDebugging, g) + j * sizeof(_dummy.g[0]); } - static int f_offset(int j) { return offset_of(RegistersForDebugging, f) + j * sizeof(_dummy.f[0]); } - static int d_offset(int j) { return offset_of(RegistersForDebugging, d) + (j / 2) * sizeof(_dummy.d[0]); } - - // gen asm code to save regs - static void save_registers(MacroAssembler* a); - - // restore global registers in case C code disturbed them - static void restore_registers(MacroAssembler* a, Register r); -}; - - -// MacroAssembler extends Assembler by a few frequently used macros. -// -// Most of the standard SPARC synthetic ops are defined here. -// Instructions for which a 'better' code sequence exists depending -// on arguments should also go in here. - -#define JMP2(r1, r2) jmp(r1, r2, __FILE__, __LINE__) -#define JMP(r1, off) jmp(r1, off, __FILE__, __LINE__) -#define JUMP(a, temp, off) jump(a, temp, off, __FILE__, __LINE__) -#define JUMPL(a, temp, d, off) jumpl(a, temp, d, off, __FILE__, __LINE__) - - -class MacroAssembler : public Assembler { - // code patchers need various routines like inv_wdisp() - friend class NativeInstruction; - friend class NativeGeneralJump; - friend class Relocation; - friend class Label; - - protected: - static int patched_branch(int dest_pos, int inst, int inst_pos); - static int branch_destination(int inst, int pos); - - // Support for VM calls - // This is the base routine called by the different versions of call_VM_leaf. The interpreter - // may customize this version by overriding it for its purposes (e.g., to save/restore - // additional registers when doing a VM call). - virtual void call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments); - - // - // It is imperative that all calls into the VM are handled via the call_VM macros. - // They make sure that the stack linkage is setup correctly. call_VM's correspond - // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points. - // - // This is the base routine called by the different versions of call_VM. The interpreter - // may customize this version by overriding it for its purposes (e.g., to save/restore - // additional registers when doing a VM call). - // - // A non-volatile java_thread_cache register should be specified so - // that the G2_thread value can be preserved across the call. - // (If java_thread_cache is noreg, then a slow get_thread call - // will re-initialize the G2_thread.) call_VM_base returns the register that contains the - // thread. - // - // If no last_java_sp is specified (noreg) than SP will be used instead. - - virtual void call_VM_base( - Register oop_result, // where an oop-result ends up if any; use noreg otherwise - Register java_thread_cache, // the thread if computed before ; use noreg otherwise - Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise - address entry_point, // the entry point - int number_of_arguments, // the number of arguments (w/o thread) to pop after call - bool check_exception=true // flag which indicates if exception should be checked - ); - - public: - MacroAssembler(CodeBuffer* code) : Assembler(code) {} - - // This routine should emit JVMTI PopFrame and ForceEarlyReturn handling code. - // The implementation is only non-empty for the InterpreterMacroAssembler, - // as only the interpreter handles and ForceEarlyReturn PopFrame requests. - virtual void check_and_handle_popframe(Register scratch_reg); - virtual void check_and_handle_earlyret(Register scratch_reg); - - // Support for NULL-checks - // - // Generates code that causes a NULL OS exception if the content of reg is NULL. - // If the accessed location is M[reg + offset] and the offset is known, provide the - // offset. No explicit code generation is needed if the offset is within a certain - // range (0 <= offset <= page_size). - // - // FIXME: Currently not done for SPARC - - void null_check(Register reg, int offset = -1); - static bool needs_explicit_null_check(intptr_t offset); - static bool uses_implicit_null_check(void* address); - - // support for delayed instructions - MacroAssembler* delayed() { Assembler::delayed(); return this; } - - // branches that use right instruction for v8 vs. v9 - inline void br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none ); - inline void br( Condition c, bool a, Predict p, Label& L ); - - inline void fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none ); - inline void fb( Condition c, bool a, Predict p, Label& L ); - - // compares register with zero (32 bit) and branches (V9 and V8 instructions) - void cmp_zero_and_br( Condition c, Register s1, Label& L, bool a = false, Predict p = pn ); - // Compares a pointer register with zero and branches on (not)null. - // Does a test & branch on 32-bit systems and a register-branch on 64-bit. - void br_null ( Register s1, bool a, Predict p, Label& L ); - void br_notnull( Register s1, bool a, Predict p, Label& L ); - - // - // Compare registers and branch with nop in delay slot or cbcond without delay slot. - // - // ATTENTION: use these instructions with caution because cbcond instruction - // has very short distance: 512 instructions (2Kbyte). - - // Compare integer (32 bit) values (icc only). - void cmp_and_br_short(Register s1, Register s2, Condition c, Predict p, Label& L); - void cmp_and_br_short(Register s1, int simm13a, Condition c, Predict p, Label& L); - // Platform depending version for pointer compare (icc on !LP64 and xcc on LP64). - void cmp_and_brx_short(Register s1, Register s2, Condition c, Predict p, Label& L); - void cmp_and_brx_short(Register s1, int simm13a, Condition c, Predict p, Label& L); - - // Short branch version for compares a pointer pwith zero. - void br_null_short ( Register s1, Predict p, Label& L ); - void br_notnull_short( Register s1, Predict p, Label& L ); - - // unconditional short branch - void ba_short(Label& L); - - // Branch on icc.z (true or not). - void br_icc_zero(bool iszero, Predict p, Label &L); - - inline void bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none ); - inline void bp( Condition c, bool a, CC cc, Predict p, Label& L ); - - // Branch that tests xcc in LP64 and icc in !LP64 - inline void brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none ); - inline void brx( Condition c, bool a, Predict p, Label& L ); - - // unconditional branch - inline void ba( Label& L ); - - // Branch that tests fp condition codes - inline void fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none ); - inline void fbp( Condition c, bool a, CC cc, Predict p, Label& L ); - - // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual) - inline void cmp( Register s1, Register s2 ); - inline void cmp( Register s1, int simm13a ); - - inline void jmp( Register s1, Register s2 ); - inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); - - // Check if the call target is out of wdisp30 range (relative to the code cache) - static inline bool is_far_target(address d); - inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); - inline void call( address d, RelocationHolder const& rspec); - - inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); - inline void call( Label& L, RelocationHolder const& rspec); - - inline void callr( Register s1, Register s2 ); - inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); - - inline void tst( Register s ); - - inline void ret( bool trace = false ); - inline void retl( bool trace = false ); - - // Required platform-specific helpers for Label::patch_instructions. - // They _shadow_ the declarations in AbstractAssembler, which are undefined. - void pd_patch_instruction(address branch, address target, const char* file, int line); - - // sethi Macro handles optimizations and relocations -private: - void internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable); -public: - void sethi(const AddressLiteral& addrlit, Register d); - void patchable_sethi(const AddressLiteral& addrlit, Register d); - - // compute the number of instructions for a sethi/set - static int insts_for_sethi( address a, bool worst_case = false ); - static int worst_case_insts_for_set(); - - // set may be either setsw or setuw (high 32 bits may be zero or sign) -private: - void internal_set(const AddressLiteral& al, Register d, bool ForceRelocatable); - static int insts_for_internal_set(intptr_t value); -public: - void set(const AddressLiteral& addrlit, Register d); - void set(intptr_t value, Register d); - void set(address addr, Register d, RelocationHolder const& rspec); - static int insts_for_set(intptr_t value) { return insts_for_internal_set(value); } - - void patchable_set(const AddressLiteral& addrlit, Register d); - void patchable_set(intptr_t value, Register d); - void set64(jlong value, Register d, Register tmp); - static int insts_for_set64(jlong value); - - // sign-extend 32 to 64 - inline void signx( Register s, Register d ); - inline void signx( Register d ); - - inline void not1( Register s, Register d ); - inline void not1( Register d ); - - inline void neg( Register s, Register d ); - inline void neg( Register d ); - - inline void cas( Register s1, Register s2, Register d); - inline void casx( Register s1, Register s2, Register d); - // Functions for isolating 64 bit atomic swaps for LP64 - // cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's - inline void cas_ptr( Register s1, Register s2, Register d); - - // Resolve a jobject or jweak - void resolve_jobject(Register value, Register tmp); - - // Functions for isolating 64 bit shifts for LP64 - inline void sll_ptr( Register s1, Register s2, Register d ); - inline void sll_ptr( Register s1, int imm6a, Register d ); - inline void sll_ptr( Register s1, RegisterOrConstant s2, Register d ); - inline void srl_ptr( Register s1, Register s2, Register d ); - inline void srl_ptr( Register s1, int imm6a, Register d ); - - // little-endian - inline void casl( Register s1, Register s2, Register d); - inline void casxl( Register s1, Register s2, Register d); - - inline void inc( Register d, int const13 = 1 ); - inline void inccc( Register d, int const13 = 1 ); - - inline void dec( Register d, int const13 = 1 ); - inline void deccc( Register d, int const13 = 1 ); - - using Assembler::add; - inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype); - inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec); - inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0); - inline void add(const Address& a, Register d, int offset = 0); - - using Assembler::andn; - inline void andn( Register s1, RegisterOrConstant s2, Register d); - - inline void btst( Register s1, Register s2 ); - inline void btst( int simm13a, Register s ); - - inline void bset( Register s1, Register s2 ); - inline void bset( int simm13a, Register s ); - - inline void bclr( Register s1, Register s2 ); - inline void bclr( int simm13a, Register s ); - - inline void btog( Register s1, Register s2 ); - inline void btog( int simm13a, Register s ); - - inline void clr( Register d ); - - inline void clrb( Register s1, Register s2); - inline void clrh( Register s1, Register s2); - inline void clr( Register s1, Register s2); - inline void clrx( Register s1, Register s2); - - inline void clrb( Register s1, int simm13a); - inline void clrh( Register s1, int simm13a); - inline void clr( Register s1, int simm13a); - inline void clrx( Register s1, int simm13a); - - // copy & clear upper word - inline void clruw( Register s, Register d ); - // clear upper word - inline void clruwu( Register d ); - - using Assembler::ldsb; - using Assembler::ldsh; - using Assembler::ldsw; - using Assembler::ldub; - using Assembler::lduh; - using Assembler::lduw; - using Assembler::ldx; - using Assembler::ldd; - -#ifdef ASSERT - // ByteSize is only a class when ASSERT is defined, otherwise it's an int. - inline void ld(Register s1, ByteSize simm13a, Register d); -#endif - - inline void ld(Register s1, Register s2, Register d); - inline void ld(Register s1, int simm13a, Register d); - - inline void ldsb(const Address& a, Register d, int offset = 0); - inline void ldsh(const Address& a, Register d, int offset = 0); - inline void ldsw(const Address& a, Register d, int offset = 0); - inline void ldub(const Address& a, Register d, int offset = 0); - inline void lduh(const Address& a, Register d, int offset = 0); - inline void lduw(const Address& a, Register d, int offset = 0); - inline void ldx( const Address& a, Register d, int offset = 0); - inline void ld( const Address& a, Register d, int offset = 0); - inline void ldd( const Address& a, Register d, int offset = 0); - - inline void ldub(Register s1, RegisterOrConstant s2, Register d ); - inline void ldsb(Register s1, RegisterOrConstant s2, Register d ); - inline void lduh(Register s1, RegisterOrConstant s2, Register d ); - inline void ldsh(Register s1, RegisterOrConstant s2, Register d ); - inline void lduw(Register s1, RegisterOrConstant s2, Register d ); - inline void ldsw(Register s1, RegisterOrConstant s2, Register d ); - inline void ldx( Register s1, RegisterOrConstant s2, Register d ); - inline void ld( Register s1, RegisterOrConstant s2, Register d ); - inline void ldd( Register s1, RegisterOrConstant s2, Register d ); - - using Assembler::ldf; - inline void ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d); - inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0); - - // little-endian - inline void lduwl(Register s1, Register s2, Register d); - inline void ldswl(Register s1, Register s2, Register d); - inline void ldxl( Register s1, Register s2, Register d); - inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d); - - // membar psuedo instruction. takes into account target memory model. - inline void membar( Assembler::Membar_mask_bits const7a ); - - // returns if membar generates anything. - inline bool membar_has_effect( Assembler::Membar_mask_bits const7a ); - - // mov pseudo instructions - inline void mov( Register s, Register d); - - inline void mov_or_nop( Register s, Register d); - - inline void mov( int simm13a, Register d); - - using Assembler::prefetch; - inline void prefetch(const Address& a, PrefetchFcn F, int offset = 0); - - using Assembler::stb; - using Assembler::sth; - using Assembler::stw; - using Assembler::stx; - using Assembler::std; - -#ifdef ASSERT - // ByteSize is only a class when ASSERT is defined, otherwise it's an int. - inline void st(Register d, Register s1, ByteSize simm13a); -#endif - - inline void st(Register d, Register s1, Register s2); - inline void st(Register d, Register s1, int simm13a); - - inline void stb(Register d, const Address& a, int offset = 0 ); - inline void sth(Register d, const Address& a, int offset = 0 ); - inline void stw(Register d, const Address& a, int offset = 0 ); - inline void stx(Register d, const Address& a, int offset = 0 ); - inline void st( Register d, const Address& a, int offset = 0 ); - inline void std(Register d, const Address& a, int offset = 0 ); - - inline void stb(Register d, Register s1, RegisterOrConstant s2 ); - inline void sth(Register d, Register s1, RegisterOrConstant s2 ); - inline void stw(Register d, Register s1, RegisterOrConstant s2 ); - inline void stx(Register d, Register s1, RegisterOrConstant s2 ); - inline void std(Register d, Register s1, RegisterOrConstant s2 ); - inline void st( Register d, Register s1, RegisterOrConstant s2 ); - - using Assembler::stf; - inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2); - inline void stf(FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset = 0); - - // Note: offset is added to s2. - using Assembler::sub; - inline void sub(Register s1, RegisterOrConstant s2, Register d, int offset = 0); - - using Assembler::swap; - inline void swap(const Address& a, Register d, int offset = 0); - - // address pseudos: make these names unlike instruction names to avoid confusion - inline intptr_t load_pc_address( Register reg, int bytes_to_skip ); - inline void load_contents(const AddressLiteral& addrlit, Register d, int offset = 0); - inline void load_bool_contents(const AddressLiteral& addrlit, Register d, int offset = 0); - inline void load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset = 0); - inline void store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0); - inline void store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0); - inline void jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset = 0); - inline void jump_to(const AddressLiteral& addrlit, Register temp, int offset = 0); - inline void jump_indirect_to(Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0); - - // ring buffer traceable jumps - - void jmp2( Register r1, Register r2, const char* file, int line ); - void jmp ( Register r1, int offset, const char* file, int line ); - - void jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line); - void jump (const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line); - - - // argument pseudos: - - inline void load_argument( Argument& a, Register d ); - inline void store_argument( Register s, Argument& a ); - inline void store_ptr_argument( Register s, Argument& a ); - inline void store_float_argument( FloatRegister s, Argument& a ); - inline void store_double_argument( FloatRegister s, Argument& a ); - inline void store_long_argument( Register s, Argument& a ); - - // handy macros: - - inline void round_to( Register r, int modulus ); - - // -------------------------------------------------- - - // Functions for isolating 64 bit loads for LP64 - // ld_ptr will perform ld for 32 bit VM's and ldx for 64 bit VM's - // st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's - inline void ld_ptr(Register s1, Register s2, Register d); - inline void ld_ptr(Register s1, int simm13a, Register d); - inline void ld_ptr(Register s1, RegisterOrConstant s2, Register d); - inline void ld_ptr(const Address& a, Register d, int offset = 0); - inline void st_ptr(Register d, Register s1, Register s2); - inline void st_ptr(Register d, Register s1, int simm13a); - inline void st_ptr(Register d, Register s1, RegisterOrConstant s2); - inline void st_ptr(Register d, const Address& a, int offset = 0); - -#ifdef ASSERT - // ByteSize is only a class when ASSERT is defined, otherwise it's an int. - inline void ld_ptr(Register s1, ByteSize simm13a, Register d); - inline void st_ptr(Register d, Register s1, ByteSize simm13a); -#endif - - // ld_long will perform ldd for 32 bit VM's and ldx for 64 bit VM's - // st_long will perform std for 32 bit VM's and stx for 64 bit VM's - inline void ld_long(Register s1, Register s2, Register d); - inline void ld_long(Register s1, int simm13a, Register d); - inline void ld_long(Register s1, RegisterOrConstant s2, Register d); - inline void ld_long(const Address& a, Register d, int offset = 0); - inline void st_long(Register d, Register s1, Register s2); - inline void st_long(Register d, Register s1, int simm13a); - inline void st_long(Register d, Register s1, RegisterOrConstant s2); - inline void st_long(Register d, const Address& a, int offset = 0); - - // Helpers for address formation. - // - They emit only a move if s2 is a constant zero. - // - If dest is a constant and either s1 or s2 is a register, the temp argument is required and becomes the result. - // - If dest is a register and either s1 or s2 is a non-simm13 constant, the temp argument is required and used to materialize the constant. - RegisterOrConstant regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg); - RegisterOrConstant regcon_inc_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg); - RegisterOrConstant regcon_sll_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg); - - RegisterOrConstant ensure_simm13_or_reg(RegisterOrConstant src, Register temp) { - if (is_simm13(src.constant_or_zero())) - return src; // register or short constant - guarantee(temp != noreg, "constant offset overflow"); - set(src.as_constant(), temp); - return temp; - } - - // -------------------------------------------------- - - public: - // traps as per trap.h (SPARC ABI?) - - void breakpoint_trap(); - void breakpoint_trap(Condition c, CC cc); - - void safepoint_poll(Label& slow_path, bool a, Register thread_reg, Register temp_reg); - - // Stack frame creation/removal - void enter(); - void leave(); - - // Manipulation of C++ bools - // These are idioms to flag the need for care with accessing bools but on - // this platform we assume byte size - - inline void stbool(Register d, const Address& a); - inline void ldbool(const Address& a, Register d); - inline void movbool( bool boolconst, Register d); - - void resolve_oop_handle(Register result, Register tmp); - void load_mirror(Register mirror, Register method, Register tmp); - - // klass oop manipulations if compressed - void load_klass(Register src_oop, Register klass); - void store_klass(Register klass, Register dst_oop); - void store_klass_gap(Register s, Register dst_oop); - - // oop manipulations - void access_store_at(BasicType type, DecoratorSet decorators, - Register src, Address dst, Register tmp); - void access_load_at(BasicType type, DecoratorSet decorators, - Address src, Register dst, Register tmp); - - void load_heap_oop(const Address& s, Register d, - Register tmp = noreg, DecoratorSet decorators = 0); - void load_heap_oop(Register s1, Register s2, Register d, - Register tmp = noreg, DecoratorSet decorators = 0); - void load_heap_oop(Register s1, int simm13a, Register d, - Register tmp = noreg, DecoratorSet decorators = 0); - void load_heap_oop(Register s1, RegisterOrConstant s2, Register d, - Register tmp = noreg, DecoratorSet decorators = 0); - void store_heap_oop(Register d, Register s1, Register s2, - Register tmp = noreg, DecoratorSet decorators = 0); - void store_heap_oop(Register d, Register s1, int simm13a, - Register tmp = noreg, DecoratorSet decorators = 0); - void store_heap_oop(Register d, const Address& a, int offset = 0, - Register tmp = noreg, DecoratorSet decorators = 0); - - void encode_heap_oop(Register src, Register dst); - void encode_heap_oop(Register r) { - encode_heap_oop(r, r); - } - void decode_heap_oop(Register src, Register dst); - void decode_heap_oop(Register r) { - decode_heap_oop(r, r); - } - void encode_heap_oop_not_null(Register r); - void decode_heap_oop_not_null(Register r); - void encode_heap_oop_not_null(Register src, Register dst); - void decode_heap_oop_not_null(Register src, Register dst); - - void encode_klass_not_null(Register r); - void decode_klass_not_null(Register r); - void encode_klass_not_null(Register src, Register dst); - void decode_klass_not_null(Register src, Register dst); - - // Support for managing the JavaThread pointer (i.e.; the reference to - // thread-local information). - void get_thread(); // load G2_thread - void verify_thread(); // verify G2_thread contents - void save_thread (const Register threache); // save to cache - void restore_thread(const Register thread_cache); // restore from cache - - // Support for last Java frame (but use call_VM instead where possible) - void set_last_Java_frame(Register last_java_sp, Register last_Java_pc); - void reset_last_Java_frame(void); - - // Call into the VM. - // Passes the thread pointer (in O0) as a prepended argument. - // Makes sure oop return values are visible to the GC. - void call_VM(Register oop_result, address entry_point, int number_of_arguments = 0, bool check_exceptions = true); - void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true); - void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true); - void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); - - // these overloadings are not presently used on SPARC: - void call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true); - void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true); - void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true); - void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true); - - void call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments = 0); - void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1); - void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2); - void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3); - - void get_vm_result (Register oop_result); - void get_vm_result_2(Register metadata_result); - - // vm result is currently getting hijacked to for oop preservation - void set_vm_result(Register oop_result); - - // Emit the CompiledIC call idiom - void ic_call(address entry, bool emit_delay = true, jint method_index = 0); - - // if call_VM_base was called with check_exceptions=false, then call - // check_and_forward_exception to handle exceptions when it is safe - void check_and_forward_exception(Register scratch_reg); - - // Returns the byte size of the instructions generated by decode_klass_not_null(). - static int instr_size_for_decode_klass_not_null(); - - // if heap base register is used - reinit it with the correct value - void reinit_heapbase(); - - // Debugging - void _verify_oop(Register reg, const char * msg, const char * file, int line); - void _verify_oop_addr(Address addr, const char * msg, const char * file, int line); - - // TODO: verify_method and klass metadata (compare against vptr?) - void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} - void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){} - -#define verify_oop(reg) _verify_oop(reg, "broken oop " #reg, __FILE__, __LINE__) -#define verify_oop_addr(addr) _verify_oop_addr(addr, "broken oop addr ", __FILE__, __LINE__) -#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__) -#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__) - - void stop(const char* msg); // prints msg, dumps registers and stops execution - void warn(const char* msg); // prints msg, but don't stop - void untested(const char* what = ""); - void unimplemented(const char* what = ""); - void should_not_reach_here() { stop("should not reach here"); } - - // oops in code - AddressLiteral allocate_oop_address(jobject obj); // allocate_index - AddressLiteral constant_oop_address(jobject obj); // find_index - inline void set_oop (jobject obj, Register d); // uses allocate_oop_address - inline void set_oop_constant (jobject obj, Register d); // uses constant_oop_address - inline void set_oop (const AddressLiteral& obj_addr, Register d); // same as load_address - - // metadata in code that we have to keep track of - AddressLiteral allocate_metadata_address(Metadata* obj); // allocate_index - AddressLiteral constant_metadata_address(Metadata* obj); // find_index - inline void set_metadata (Metadata* obj, Register d); // uses allocate_metadata_address - inline void set_metadata_constant (Metadata* obj, Register d); // uses constant_metadata_address - inline void set_metadata (const AddressLiteral& obj_addr, Register d); // same as load_address - - void set_narrow_oop( jobject obj, Register d ); - void set_narrow_klass( Klass* k, Register d ); - - // nop padding - void align(int modulus); - - // declare a safepoint - void safepoint(); - - // factor out part of stop into subroutine to save space - void stop_subroutine(); - // factor out part of verify_oop into subroutine to save space - void verify_oop_subroutine(); - - // side-door communication with signalHandler in os_solaris.cpp - static address _verify_oop_implicit_branch[3]; - - int total_frame_size_in_bytes(int extraWords); - - // used when extraWords known statically - void save_frame(int extraWords = 0); - void save_frame_c1(int size_in_bytes); - // make a frame, and simultaneously pass up one or two register value - // into the new register window - void save_frame_and_mov(int extraWords, Register s1, Register d1, Register s2 = Register(), Register d2 = Register()); - - // give no. (outgoing) params, calc # of words will need on frame - void calc_mem_param_words(Register Rparam_words, Register Rresult); - - // used to calculate frame size dynamically - // result is in bytes and must be negated for save inst - void calc_frame_size(Register extraWords, Register resultReg); - - // calc and also save - void calc_frame_size_and_save(Register extraWords, Register resultReg); - - static void debug(char* msg, RegistersForDebugging* outWindow); - - // implementations of bytecodes used by both interpreter and compiler - - void lcmp( Register Ra_hi, Register Ra_low, - Register Rb_hi, Register Rb_low, - Register Rresult); - - void lneg( Register Rhi, Register Rlow ); - - void lshl( Register Rin_high, Register Rin_low, Register Rcount, - Register Rout_high, Register Rout_low, Register Rtemp ); - - void lshr( Register Rin_high, Register Rin_low, Register Rcount, - Register Rout_high, Register Rout_low, Register Rtemp ); - - void lushr( Register Rin_high, Register Rin_low, Register Rcount, - Register Rout_high, Register Rout_low, Register Rtemp ); - - void lcmp( Register Ra, Register Rb, Register Rresult); - - // Load and store values by size and signed-ness - void load_sized_value( Address src, Register dst, size_t size_in_bytes, bool is_signed); - void store_sized_value(Register src, Address dst, size_t size_in_bytes); - - void float_cmp( bool is_float, int unordered_result, - FloatRegister Fa, FloatRegister Fb, - Register Rresult); - - void save_all_globals_into_locals(); - void restore_globals_from_locals(); - - // These set the icc condition code to equal if the lock succeeded - // and notEqual if it failed and requires a slow case - void compiler_lock_object(Register Roop, Register Rmark, Register Rbox, - Register Rscratch, - BiasedLockingCounters* counters = NULL, - bool try_bias = UseBiasedLocking); - void compiler_unlock_object(Register Roop, Register Rmark, Register Rbox, - Register Rscratch, - bool try_bias = UseBiasedLocking); - - // Biased locking support - // Upon entry, lock_reg must point to the lock record on the stack, - // obj_reg must contain the target object, and mark_reg must contain - // the target object's header. - // Destroys mark_reg if an attempt is made to bias an anonymously - // biased lock. In this case a failure will go either to the slow - // case or fall through with the notEqual condition code set with - // the expectation that the slow case in the runtime will be called. - // In the fall-through case where the CAS-based lock is done, - // mark_reg is not destroyed. - void biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg, - Label& done, Label* slow_case = NULL, - BiasedLockingCounters* counters = NULL); - // Upon entry, the base register of mark_addr must contain the oop. - // Destroys temp_reg. - - // If allow_delay_slot_filling is set to true, the next instruction - // emitted after this one will go in an annulled delay slot if the - // biased locking exit case failed. - void biased_locking_exit(Address mark_addr, Register temp_reg, Label& done, bool allow_delay_slot_filling = false); - - // allocation - void eden_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 tlab_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 - Label& slow_case // continuation point if fast allocation fails - ); - void zero_memory(Register base, Register index); - void incr_allocated_bytes(RegisterOrConstant size_in_bytes, - Register t1, Register t2); - - // interface method calling - void lookup_interface_method(Register recv_klass, - Register intf_klass, - RegisterOrConstant itable_index, - Register method_result, - Register temp_reg, Register temp2_reg, - Label& no_such_interface, - bool return_method = true); - - // virtual method calling - void lookup_virtual_method(Register recv_klass, - RegisterOrConstant vtable_index, - Register method_result); - - // Test sub_klass against super_klass, with fast and slow paths. - - // The fast path produces a tri-state answer: yes / no / maybe-slow. - // One of the three labels can be NULL, meaning take the fall-through. - // If super_check_offset is -1, the value is loaded up from super_klass. - // No registers are killed, except temp_reg and temp2_reg. - // If super_check_offset is not -1, temp2_reg is not used and can be noreg. - void check_klass_subtype_fast_path(Register sub_klass, - Register super_klass, - Register temp_reg, - Register temp2_reg, - Label* L_success, - Label* L_failure, - Label* L_slow_path, - RegisterOrConstant super_check_offset = RegisterOrConstant(-1)); - - // The rest of the type check; must be wired to a corresponding fast path. - // It does not repeat the fast path logic, so don't use it standalone. - // The temp_reg can be noreg, if no temps are available. - // It can also be sub_klass or super_klass, meaning it's OK to kill that one. - // Updates the sub's secondary super cache as necessary. - void check_klass_subtype_slow_path(Register sub_klass, - Register super_klass, - Register temp_reg, - Register temp2_reg, - Register temp3_reg, - Register temp4_reg, - Label* L_success, - Label* L_failure); - - // Simplified, combined version, good for typical uses. - // Falls through on failure. - void check_klass_subtype(Register sub_klass, - Register super_klass, - Register temp_reg, - Register temp2_reg, - Label& L_success); - - // method handles (JSR 292) - // offset relative to Gargs of argument at tos[arg_slot]. - // (arg_slot == 0 means the last argument, not the first). - RegisterOrConstant argument_offset(RegisterOrConstant arg_slot, - Register temp_reg, - int extra_slot_offset = 0); - // Address of Gargs and argument_offset. - Address argument_address(RegisterOrConstant arg_slot, - Register temp_reg = noreg, - int extra_slot_offset = 0); - - // Stack overflow checking - - // Note: this clobbers G3_scratch - void bang_stack_with_offset(int offset); - - // Writes to stack successive pages until offset reached to check for - // stack overflow + shadow pages. Clobbers tsp and scratch registers. - void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch); - - // Check for reserved stack access in method being exited (for JIT) - void reserved_stack_check(); - - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset); - - void verify_tlab(); - - Condition negate_condition(Condition cond); - - // Helper functions for statistics gathering. - // Conditionally (non-atomically) increments passed counter address, preserving condition codes. - void cond_inc(Condition cond, address counter_addr, Register Rtemp1, Register Rtemp2); - // Unconditional increment. - void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2); - void inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2); - - // Use BIS for zeroing - void bis_zeroing(Register to, Register count, Register temp, Label& Ldone); - - // Update CRC-32[C] with a byte value according to constants in table - void update_byte_crc32(Register crc, Register val, Register table); - - // Reverse byte order of lower 32 bits, assuming upper 32 bits all zeros - void reverse_bytes_32(Register src, Register dst, Register tmp); - void movitof_revbytes(Register src, FloatRegister dst, Register tmp1, Register tmp2); - void movftoi_revbytes(FloatRegister src, Register dst, Register tmp1, Register tmp2); - - // CRC32 code for java.util.zip.CRC32::updateBytes0() intrinsic. - void kernel_crc32(Register crc, Register buf, Register len, Register table); - // Fold 128-bit data chunk - void fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register buf, int offset); - void fold_128bit_crc32(Register xcrc_hi, Register xcrc_lo, Register xK_hi, Register xK_lo, Register xtmp_hi, Register xtmp_lo, Register xbuf_hi, Register xbuf_lo); - // Fold 8-bit data - void fold_8bit_crc32(Register xcrc, Register table, Register xtmp, Register tmp); - void fold_8bit_crc32(Register crc, Register table, Register tmp); - // CRC32C code for java.util.zip.CRC32C::updateBytes/updateDirectByteBuffer intrinsic. - void kernel_crc32c(Register crc, Register buf, Register len, Register table); - -}; - -/** - * class SkipIfEqual: - * - * Instantiating this class will result in assembly code being output that will - * jump around any code emitted between the creation of the instance and it's - * automatic destruction at the end of a scope block, depending on the value of - * the flag passed to the constructor, which will be checked at run-time. - */ -class SkipIfEqual : public StackObj { - private: - MacroAssembler* _masm; - Label _label; - - public: - // 'temp' is a temp register that this object can use (and trash) - SkipIfEqual(MacroAssembler*, Register temp, - const bool* flag_addr, Assembler::Condition condition); - ~SkipIfEqual(); -}; - -#endif // CPU_SPARC_MACROASSEMBLER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.inline.hpp +++ /dev/null @@ -1,715 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_MACROASSEMBLER_SPARC_INLINE_HPP -#define CPU_SPARC_MACROASSEMBLER_SPARC_INLINE_HPP - -#include "asm/assembler.inline.hpp" -#include "asm/macroAssembler.hpp" -#include "asm/codeBuffer.hpp" -#include "code/codeCache.hpp" - -inline bool Address::is_simm13(int offset) { return Assembler::is_simm13(disp() + offset); } - - -inline int AddressLiteral::low10() const { - return Assembler::low10(value()); -} - - -inline void MacroAssembler::pd_patch_instruction(address branch, address target, const char* file, int line) { - jint& stub_inst = *(jint*) branch; - stub_inst = patched_branch(target - branch, stub_inst, 0); -} - -// Use the right loads/stores for the platform -inline void MacroAssembler::ld_ptr( Register s1, Register s2, Register d ) { - Assembler::ldx(s1, s2, d); -} - -inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) { - Assembler::ldx(s1, simm13a, d); -} - -#ifdef ASSERT -// ByteSize is only a class when ASSERT is defined, otherwise it's an int. -inline void MacroAssembler::ld_ptr( Register s1, ByteSize simm13a, Register d ) { - ld_ptr(s1, in_bytes(simm13a), d); -} -#endif - -inline void MacroAssembler::ld_ptr( Register s1, RegisterOrConstant s2, Register d ) { - ldx(s1, s2, d); -} - -inline void MacroAssembler::ld_ptr(const Address& a, Register d, int offset) { - ldx(a, d, offset); -} - -inline void MacroAssembler::st_ptr( Register d, Register s1, Register s2 ) { - Assembler::stx(d, s1, s2); -} - -inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) { - Assembler::stx(d, s1, simm13a); -} - -#ifdef ASSERT -// ByteSize is only a class when ASSERT is defined, otherwise it's an int. -inline void MacroAssembler::st_ptr( Register d, Register s1, ByteSize simm13a ) { - st_ptr(d, s1, in_bytes(simm13a)); -} -#endif - -inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterOrConstant s2 ) { - stx(d, s1, s2); -} - -inline void MacroAssembler::st_ptr(Register d, const Address& a, int offset) { - stx(d, a, offset); -} - -// Use the right loads/stores for the platform -inline void MacroAssembler::ld_long( Register s1, Register s2, Register d ) { - Assembler::ldx(s1, s2, d); -} - -inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) { - Assembler::ldx(s1, simm13a, d); -} - -inline void MacroAssembler::ld_long( Register s1, RegisterOrConstant s2, Register d ) { - ldx(s1, s2, d); -} - -inline void MacroAssembler::ld_long(const Address& a, Register d, int offset) { - ldx(a, d, offset); -} - -inline void MacroAssembler::st_long( Register d, Register s1, Register s2 ) { - Assembler::stx(d, s1, s2); -} - -inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) { - Assembler::stx(d, s1, simm13a); -} - -inline void MacroAssembler::st_long( Register d, Register s1, RegisterOrConstant s2 ) { - stx(d, s1, s2); -} - -inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) { - stx(d, a, offset); -} - -inline void MacroAssembler::stbool(Register d, const Address& a) { stb(d, a); } -inline void MacroAssembler::ldbool(const Address& a, Register d) { ldub(a, d); } -inline void MacroAssembler::movbool( bool boolconst, Register d) { mov( (int) boolconst, d); } - - -inline void MacroAssembler::signx( Register s, Register d ) { sra( s, G0, d); } -inline void MacroAssembler::signx( Register d ) { sra( d, G0, d); } - -inline void MacroAssembler::not1( Register s, Register d ) { xnor( s, G0, d ); } -inline void MacroAssembler::not1( Register d ) { xnor( d, G0, d ); } - -inline void MacroAssembler::neg( Register s, Register d ) { sub( G0, s, d ); } -inline void MacroAssembler::neg( Register d ) { sub( G0, d, d ); } - -inline void MacroAssembler::cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); } -inline void MacroAssembler::casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); } - -// Functions for isolating 64 bit atomic swaps for LP64 -// cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's -inline void MacroAssembler::cas_ptr( Register s1, Register s2, Register d) { - casx( s1, s2, d ); -} - -// Functions for isolating 64 bit shifts for LP64 - -inline void MacroAssembler::sll_ptr( Register s1, Register s2, Register d ) { - Assembler::sllx(s1, s2, d); -} - -inline void MacroAssembler::sll_ptr( Register s1, int imm6a, Register d ) { - Assembler::sllx(s1, imm6a, d); -} - -inline void MacroAssembler::srl_ptr( Register s1, Register s2, Register d ) { - Assembler::srlx(s1, s2, d); -} - -inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) { - Assembler::srlx(s1, imm6a, d); -} - -inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Register d ) { - if (s2.is_register()) sll_ptr(s1, s2.as_register(), d); - else sll_ptr(s1, s2.as_constant(), d); -} - -inline void MacroAssembler::casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); } -inline void MacroAssembler::casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); } - -inline void MacroAssembler::inc( Register d, int const13 ) { add( d, const13, d); } -inline void MacroAssembler::inccc( Register d, int const13 ) { addcc( d, const13, d); } - -inline void MacroAssembler::dec( Register d, int const13 ) { sub( d, const13, d); } -inline void MacroAssembler::deccc( Register d, int const13 ) { subcc( d, const13, d); } - -// Use the right branch for the platform - -inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) { - Assembler::bp(c, a, icc, p, d, rt); -} - -inline void MacroAssembler::br( Condition c, bool a, Predict p, Label& L ) { - // See note[+] on 'avoid_pipeline_stall()', in "assembler_sparc.inline.hpp". - avoid_pipeline_stall(); - br(c, a, p, target(L)); -} - - -// Branch that tests either xcc or icc depending on the -// architecture compiled (LP64 or not) -inline void MacroAssembler::brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) { - Assembler::bp(c, a, xcc, p, d, rt); -} - -inline void MacroAssembler::brx( Condition c, bool a, Predict p, Label& L ) { - avoid_pipeline_stall(); - brx(c, a, p, target(L)); -} - -inline void MacroAssembler::ba( Label& L ) { - br(always, false, pt, L); -} - -// Warning: V9 only functions -inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) { - Assembler::bp(c, a, cc, p, d, rt); -} - -inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, Label& L ) { - Assembler::bp(c, a, cc, p, L); -} - -inline void MacroAssembler::fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) { - fbp(c, a, fcc0, p, d, rt); -} - -inline void MacroAssembler::fb( Condition c, bool a, Predict p, Label& L ) { - avoid_pipeline_stall(); - fb(c, a, p, target(L)); -} - -inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) { - Assembler::fbp(c, a, cc, p, d, rt); -} - -inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, Label& L ) { - Assembler::fbp(c, a, cc, p, L); -} - -inline void MacroAssembler::jmp( Register s1, Register s2 ) { jmpl( s1, s2, G0 ); } -inline void MacroAssembler::jmp( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, G0, rspec); } - -inline bool MacroAssembler::is_far_target(address d) { - if (ForceUnreachable) { - // References outside the code cache should be treated as far - return d < CodeCache::low_bound() || d > CodeCache::high_bound(); - } - return !is_in_wdisp30_range(d, CodeCache::low_bound()) || !is_in_wdisp30_range(d, CodeCache::high_bound()); -} - -// Call with a check to see if we need to deal with the added -// expense of relocation and if we overflow the displacement -// of the quick call instruction. -inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { - MacroAssembler::call(d, Relocation::spec_simple(rt)); -} - -inline void MacroAssembler::call( address d, RelocationHolder const& rspec ) { - intptr_t disp; - // NULL is ok because it will be relocated later. - // Must change NULL to a reachable address in order to - // pass asserts here and in wdisp. - if ( d == NULL ) - d = pc(); - - // Is this address within range of the call instruction? - // If not, use the expensive instruction sequence - if (is_far_target(d)) { - relocate(rspec); - AddressLiteral dest(d); - jumpl_to(dest, O7, O7); - } else { - Assembler::call(d, rspec); - } -} - -inline void MacroAssembler::call( Label& L, relocInfo::relocType rt ) { - avoid_pipeline_stall(); - MacroAssembler::call(target(L), rt); -} - - -inline void MacroAssembler::callr( Register s1, Register s2 ) { jmpl( s1, s2, O7 ); } -inline void MacroAssembler::callr( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, O7, rspec); } - -inline void MacroAssembler::tst( Register s ) { orcc( G0, s, G0 ); } - -inline void MacroAssembler::ret( bool trace ) { - if (trace) { - mov(I7, O7); // traceable register - JMP(O7, 2 * BytesPerInstWord); - } else { - jmpl( I7, 2 * BytesPerInstWord, G0 ); - } -} - -inline void MacroAssembler::retl( bool trace ) { - if (trace) { - JMP(O7, 2 * BytesPerInstWord); - } else { - jmpl( O7, 2 * BytesPerInstWord, G0 ); - } -} - - -inline void MacroAssembler::cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); } -inline void MacroAssembler::cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); } - -// Note: All MacroAssembler::set_foo functions are defined out-of-line. - - -// Loads the current PC of the following instruction as an immediate value in -// 2 instructions. All PCs in the CodeCache are within 2 Gig of each other. -inline intptr_t MacroAssembler::load_pc_address( Register reg, int bytes_to_skip ) { - intptr_t thepc = (intptr_t)pc() + 2*BytesPerInstWord + bytes_to_skip; - Unimplemented(); - return thepc; -} - - -inline void MacroAssembler::load_contents(const AddressLiteral& addrlit, Register d, int offset) { - assert_not_delayed(); - if (ForceUnreachable) { - patchable_sethi(addrlit, d); - } else { - sethi(addrlit, d); - } - ld(d, addrlit.low10() + offset, d); -} - - -inline void MacroAssembler::load_bool_contents(const AddressLiteral& addrlit, Register d, int offset) { - assert_not_delayed(); - if (ForceUnreachable) { - patchable_sethi(addrlit, d); - } else { - sethi(addrlit, d); - } - ldub(d, addrlit.low10() + offset, d); -} - - -inline void MacroAssembler::load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset) { - assert_not_delayed(); - if (ForceUnreachable) { - patchable_sethi(addrlit, d); - } else { - sethi(addrlit, d); - } - ld_ptr(d, addrlit.low10() + offset, d); -} - - -inline void MacroAssembler::store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) { - assert_not_delayed(); - if (ForceUnreachable) { - patchable_sethi(addrlit, temp); - } else { - sethi(addrlit, temp); - } - st(s, temp, addrlit.low10() + offset); -} - - -inline void MacroAssembler::store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) { - assert_not_delayed(); - if (ForceUnreachable) { - patchable_sethi(addrlit, temp); - } else { - sethi(addrlit, temp); - } - st_ptr(s, temp, addrlit.low10() + offset); -} - - -// This code sequence is relocatable to any address, even on LP64. -inline void MacroAssembler::jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset) { - assert_not_delayed(); - // Force fixed length sethi because NativeJump and NativeFarCall don't handle - // variable length instruction streams. - patchable_sethi(addrlit, temp); - jmpl(temp, addrlit.low10() + offset, d); -} - - -inline void MacroAssembler::jump_to(const AddressLiteral& addrlit, Register temp, int offset) { - jumpl_to(addrlit, temp, G0, offset); -} - - -inline void MacroAssembler::jump_indirect_to(Address& a, Register temp, - int ld_offset, int jmp_offset) { - assert_not_delayed(); - //sethi(al); // sethi is caller responsibility for this one - ld_ptr(a, temp, ld_offset); - jmp(temp, jmp_offset); -} - - -inline void MacroAssembler::set_metadata(Metadata* obj, Register d) { - set_metadata(allocate_metadata_address(obj), d); -} - -inline void MacroAssembler::set_metadata_constant(Metadata* obj, Register d) { - set_metadata(constant_metadata_address(obj), d); -} - -inline void MacroAssembler::set_metadata(const AddressLiteral& obj_addr, Register d) { - assert(obj_addr.rspec().type() == relocInfo::metadata_type, "must be a metadata reloc"); - set(obj_addr, d); -} - -inline void MacroAssembler::set_oop(jobject obj, Register d) { - set_oop(allocate_oop_address(obj), d); -} - - -inline void MacroAssembler::set_oop_constant(jobject obj, Register d) { - set_oop(constant_oop_address(obj), d); -} - - -inline void MacroAssembler::set_oop(const AddressLiteral& obj_addr, Register d) { - assert(obj_addr.rspec().type() == relocInfo::oop_type, "must be an oop reloc"); - set(obj_addr, d); -} - - -inline void MacroAssembler::load_argument( Argument& a, Register d ) { - if (a.is_register()) - mov(a.as_register(), d); - else - ld (a.as_address(), d); -} - -inline void MacroAssembler::store_argument( Register s, Argument& a ) { - if (a.is_register()) - mov(s, a.as_register()); - else - st_ptr (s, a.as_address()); // ABI says everything is right justified. -} - -inline void MacroAssembler::store_ptr_argument( Register s, Argument& a ) { - if (a.is_register()) - mov(s, a.as_register()); - else - st_ptr (s, a.as_address()); -} - - -inline void MacroAssembler::store_float_argument( FloatRegister s, Argument& a ) { - if (a.is_float_register()) -// V9 ABI has F1, F3, F5 are used to pass instead of O0, O1, O2 - fmov(FloatRegisterImpl::S, s, a.as_float_register() ); - else - // Floats are stored in the high half of the stack entry - // The low half is undefined per the ABI. - stf(FloatRegisterImpl::S, s, a.as_address(), sizeof(jfloat)); -} - -inline void MacroAssembler::store_double_argument( FloatRegister s, Argument& a ) { - if (a.is_float_register()) -// V9 ABI has D0, D2, D4 are used to pass instead of O0, O1, O2 - fmov(FloatRegisterImpl::D, s, a.as_double_register() ); - else - stf(FloatRegisterImpl::D, s, a.as_address()); -} - -inline void MacroAssembler::store_long_argument( Register s, Argument& a ) { - if (a.is_register()) - mov(s, a.as_register()); - else - stx(s, a.as_address()); -} - -inline void MacroAssembler::round_to( Register r, int modulus ) { - assert_not_delayed(); - inc( r, modulus - 1 ); - and3( r, -modulus, r ); -} - -inline void MacroAssembler::add(Register s1, int simm13a, Register d, relocInfo::relocType rtype) { - relocate(rtype); - add(s1, simm13a, d); -} -inline void MacroAssembler::add(Register s1, int simm13a, Register d, RelocationHolder const& rspec) { - relocate(rspec); - add(s1, simm13a, d); -} - -// form effective addresses this way: -inline void MacroAssembler::add(const Address& a, Register d, int offset) { - if (a.has_index()) add(a.base(), a.index(), d); - else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; } - if (offset != 0) add(d, offset, d); -} -inline void MacroAssembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) { - if (s2.is_register()) add(s1, s2.as_register(), d); - else { add(s1, s2.as_constant() + offset, d); offset = 0; } - if (offset != 0) add(d, offset, d); -} - -inline void MacroAssembler::andn(Register s1, RegisterOrConstant s2, Register d) { - if (s2.is_register()) andn(s1, s2.as_register(), d); - else andn(s1, s2.as_constant(), d); -} - -inline void MacroAssembler::btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); } -inline void MacroAssembler::btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); } - -inline void MacroAssembler::bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); } -inline void MacroAssembler::bset( int simm13a, Register s ) { or3( s, simm13a, s ); } - -inline void MacroAssembler::bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); } -inline void MacroAssembler::bclr( int simm13a, Register s ) { andn( s, simm13a, s ); } - -inline void MacroAssembler::btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); } -inline void MacroAssembler::btog( int simm13a, Register s ) { xor3( s, simm13a, s ); } - -inline void MacroAssembler::clr( Register d ) { or3( G0, G0, d ); } - -inline void MacroAssembler::clrb( Register s1, Register s2) { stb( G0, s1, s2 ); } -inline void MacroAssembler::clrh( Register s1, Register s2) { sth( G0, s1, s2 ); } -inline void MacroAssembler::clr( Register s1, Register s2) { stw( G0, s1, s2 ); } -inline void MacroAssembler::clrx( Register s1, Register s2) { stx( G0, s1, s2 ); } - -inline void MacroAssembler::clrb( Register s1, int simm13a) { stb( G0, s1, simm13a); } -inline void MacroAssembler::clrh( Register s1, int simm13a) { sth( G0, s1, simm13a); } -inline void MacroAssembler::clr( Register s1, int simm13a) { stw( G0, s1, simm13a); } -inline void MacroAssembler::clrx( Register s1, int simm13a) { stx( G0, s1, simm13a); } - -inline void MacroAssembler::clruw( Register s, Register d ) { srl( s, G0, d); } -inline void MacroAssembler::clruwu( Register d ) { srl( d, G0, d); } - -// Make all 32 bit loads signed so 64 bit registers maintain proper sign -inline void MacroAssembler::ld( Register s1, Register s2, Register d) { ldsw( s1, s2, d); } -inline void MacroAssembler::ld( Register s1, int simm13a, Register d) { ldsw( s1, simm13a, d); } - -#ifdef ASSERT - // ByteSize is only a class when ASSERT is defined, otherwise it's an int. -inline void MacroAssembler::ld(Register s1, ByteSize simm13a, Register d) { ldsw( s1, in_bytes(simm13a), d); } -#endif - -inline void MacroAssembler::ld( const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ld( a.base(), a.index(), d); } - else { ld( a.base(), a.disp() + offset, d); } -} - -inline void MacroAssembler::ldsb(const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ldsb(a.base(), a.index(), d); } - else { ldsb(a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::ldsh(const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ldsh(a.base(), a.index(), d); } - else { ldsh(a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::ldsw(const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ldsw(a.base(), a.index(), d); } - else { ldsw(a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::ldub(const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ldub(a.base(), a.index(), d); } - else { ldub(a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::lduh(const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); lduh(a.base(), a.index(), d); } - else { lduh(a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::lduw(const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); lduw(a.base(), a.index(), d); } - else { lduw(a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::ldd( const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ldd( a.base(), a.index(), d); } - else { ldd( a.base(), a.disp() + offset, d); } -} -inline void MacroAssembler::ldx( const Address& a, Register d, int offset) { - if (a.has_index()) { assert(offset == 0, ""); ldx( a.base(), a.index(), d); } - else { ldx( a.base(), a.disp() + offset, d); } -} - -inline void MacroAssembler::ldub(Register s1, RegisterOrConstant s2, Register d) { ldub(Address(s1, s2), d); } -inline void MacroAssembler::ldsb(Register s1, RegisterOrConstant s2, Register d) { ldsb(Address(s1, s2), d); } -inline void MacroAssembler::lduh(Register s1, RegisterOrConstant s2, Register d) { lduh(Address(s1, s2), d); } -inline void MacroAssembler::ldsh(Register s1, RegisterOrConstant s2, Register d) { ldsh(Address(s1, s2), d); } -inline void MacroAssembler::lduw(Register s1, RegisterOrConstant s2, Register d) { lduw(Address(s1, s2), d); } -inline void MacroAssembler::ldsw(Register s1, RegisterOrConstant s2, Register d) { ldsw(Address(s1, s2), d); } -inline void MacroAssembler::ldx( Register s1, RegisterOrConstant s2, Register d) { ldx( Address(s1, s2), d); } -inline void MacroAssembler::ld( Register s1, RegisterOrConstant s2, Register d) { ld( Address(s1, s2), d); } -inline void MacroAssembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); } - -inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d) { - if (s2.is_register()) ldf(w, s1, s2.as_register(), d); - else ldf(w, s1, s2.as_constant(), d); -} - -inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset) { - relocate(a.rspec(offset)); - if (a.has_index()) { - assert(offset == 0, ""); - ldf(w, a.base(), a.index(), d); - } else { - ldf(w, a.base(), a.disp() + offset, d); - } -} - -inline void MacroAssembler::lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); } -inline void MacroAssembler::ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);} -inline void MacroAssembler::ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } -inline void MacroAssembler::ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); } - -// returns if membar generates anything, obviously this code should mirror -// membar below. -inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) { - const Membar_mask_bits effective_mask = - Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore)); - return (effective_mask != 0); -} - -inline void MacroAssembler::membar( Membar_mask_bits const7a ) { - // Weakened for current Sparcs and TSO. See the v9 manual, sections 8.4.3, - // 8.4.4.3, a.31 and a.50. - // Under TSO, setting bit 3, 2, or 0 is redundant, so the only value - // of the mmask subfield of const7a that does anything that isn't done - // implicitly is StoreLoad. - const Membar_mask_bits effective_mask = - Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore)); - if (effective_mask != 0) { - Assembler::membar(effective_mask); - } -} - -inline void MacroAssembler::mov(Register s, Register d) { - if (s != d) { - or3(G0, s, d); - } else { - assert_not_delayed(); // Put something useful in the delay slot! - } -} - -inline void MacroAssembler::mov_or_nop(Register s, Register d) { - if (s != d) { - or3(G0, s, d); - } else { - nop(); - } -} - -inline void MacroAssembler::mov( int simm13a, Register d) { or3( G0, simm13a, d); } - -inline void MacroAssembler::prefetch(const Address& a, PrefetchFcn f, int offset) { - relocate(a.rspec(offset)); - assert(!a.has_index(), ""); - prefetch(a.base(), a.disp() + offset, f); -} - -inline void MacroAssembler::st(Register d, Register s1, Register s2) { stw(d, s1, s2); } -inline void MacroAssembler::st(Register d, Register s1, int simm13a) { stw(d, s1, simm13a); } - -#ifdef ASSERT -// ByteSize is only a class when ASSERT is defined, otherwise it's an int. -inline void MacroAssembler::st(Register d, Register s1, ByteSize simm13a) { stw(d, s1, in_bytes(simm13a)); } -#endif - -inline void MacroAssembler::st(Register d, const Address& a, int offset) { - if (a.has_index()) { assert(offset == 0, ""); st( d, a.base(), a.index() ); } - else { st( d, a.base(), a.disp() + offset); } -} - -inline void MacroAssembler::stb(Register d, const Address& a, int offset) { - if (a.has_index()) { assert(offset == 0, ""); stb(d, a.base(), a.index() ); } - else { stb(d, a.base(), a.disp() + offset); } -} -inline void MacroAssembler::sth(Register d, const Address& a, int offset) { - if (a.has_index()) { assert(offset == 0, ""); sth(d, a.base(), a.index() ); } - else { sth(d, a.base(), a.disp() + offset); } -} -inline void MacroAssembler::stw(Register d, const Address& a, int offset) { - if (a.has_index()) { assert(offset == 0, ""); stw(d, a.base(), a.index() ); } - else { stw(d, a.base(), a.disp() + offset); } -} -inline void MacroAssembler::std(Register d, const Address& a, int offset) { - if (a.has_index()) { assert(offset == 0, ""); std(d, a.base(), a.index() ); } - else { std(d, a.base(), a.disp() + offset); } -} -inline void MacroAssembler::stx(Register d, const Address& a, int offset) { - if (a.has_index()) { assert(offset == 0, ""); stx(d, a.base(), a.index() ); } - else { stx(d, a.base(), a.disp() + offset); } -} - -inline void MacroAssembler::stb(Register d, Register s1, RegisterOrConstant s2) { stb(d, Address(s1, s2)); } -inline void MacroAssembler::sth(Register d, Register s1, RegisterOrConstant s2) { sth(d, Address(s1, s2)); } -inline void MacroAssembler::stw(Register d, Register s1, RegisterOrConstant s2) { stw(d, Address(s1, s2)); } -inline void MacroAssembler::stx(Register d, Register s1, RegisterOrConstant s2) { stx(d, Address(s1, s2)); } -inline void MacroAssembler::std(Register d, Register s1, RegisterOrConstant s2) { std(d, Address(s1, s2)); } -inline void MacroAssembler::st( Register d, Register s1, RegisterOrConstant s2) { st( d, Address(s1, s2)); } - -inline void MacroAssembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2) { - if (s2.is_register()) stf(w, d, s1, s2.as_register()); - else stf(w, d, s1, s2.as_constant()); -} - -inline void MacroAssembler::stf(FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset) { - relocate(a.rspec(offset)); - if (a.has_index()) { assert(offset == 0, ""); stf(w, d, a.base(), a.index() ); } - else { stf(w, d, a.base(), a.disp() + offset); } -} - -inline void MacroAssembler::sub(Register s1, RegisterOrConstant s2, Register d, int offset) { - if (s2.is_register()) sub(s1, s2.as_register(), d); - else { sub(s1, s2.as_constant() + offset, d); offset = 0; } - if (offset != 0) sub(d, offset, d); -} - -inline void MacroAssembler::swap(const Address& a, Register d, int offset) { - relocate(a.rspec(offset)); - if (a.has_index()) { assert(offset == 0, ""); swap(a.base(), a.index(), d ); } - else { swap(a.base(), a.disp() + offset, d); } -} -#endif // CPU_SPARC_MACROASSEMBLER_SPARC_INLINE_HPP diff --git a/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp b/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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. - * - */ - -#include "precompiled.hpp" - -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/memset_with_concurrent_readers.hpp" -#include "runtime/prefetch.inline.hpp" -#include "utilities/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" - -// An implementation of memset, for use when there may be concurrent -// readers of the region being stored into. -// -// We can't use the standard library memset if it is implemented using -// block initializing stores. Doing so can result in concurrent readers -// seeing spurious zeros. -// -// We can't use the obvious C/C++ for-loop, because the compiler may -// recognize the idiomatic loop and optimize it into a call to the -// standard library memset; we've seen exactly this happen with, for -// example, Solaris Studio 12.3. Hence the use of inline assembly -// code, hiding loops from the compiler's optimizer. -// -// We don't attempt to use the standard library memset when it is safe -// to do so. We could conservatively do so by detecting the presence -// of block initializing stores (VM_Version::has_blk_init()), but the -// implementation provided here should be sufficient. - -inline void fill_subword(void* start, void* end, int value) { - STATIC_ASSERT(BytesPerWord == 8); - assert(pointer_delta(end, start, 1) < (size_t)BytesPerWord, "precondition"); - // Dispatch on (end - start). - void* pc; - __asm__ volatile( - // offset := (7 - (end - start)) + 3 - // 3 instructions from rdpc to DISPATCH - " sub %[offset], %[end], %[offset]\n\t" // offset := start - end - " sllx %[offset], 2, %[offset]\n\t" // scale offset for instruction size of 4 - " add %[offset], 40, %[offset]\n\t" // offset += 10 * instruction size - " rd %%pc, %[pc]\n\t" // dispatch on scaled offset - " jmpl %[pc]+%[offset], %%g0\n\t" - " nop\n\t" - // DISPATCH: no direct reference, but without it the store block may be elided. - "1:\n\t" - " stb %[value], [%[end]-7]\n\t" // end[-7] = value - " stb %[value], [%[end]-6]\n\t" - " stb %[value], [%[end]-5]\n\t" - " stb %[value], [%[end]-4]\n\t" - " stb %[value], [%[end]-3]\n\t" - " stb %[value], [%[end]-2]\n\t" - " stb %[value], [%[end]-1]\n\t" // end[-1] = value - : /* only temporaries/overwritten outputs */ - [pc] "=&r" (pc), // temp - [offset] "+&r" (start) - : [end] "r" (end), - [value] "r" (value) - : "memory"); -} - -void memset_with_concurrent_readers(void* to, int value, size_t size) { - Prefetch::write(to, 0); - void* end = static_cast(to) + size; - if (size >= (size_t)BytesPerWord) { - // Fill any partial word prefix. - uintx* aligned_to = static_cast(align_up(to, BytesPerWord)); - fill_subword(to, aligned_to, value); - - // Compute fill word. - STATIC_ASSERT(BitsPerByte == 8); - STATIC_ASSERT(BitsPerWord == 64); - uintx xvalue = value & 0xff; - xvalue |= (xvalue << 8); - xvalue |= (xvalue << 16); - xvalue |= (xvalue << 32); - - uintx* aligned_end = static_cast(align_down(end, BytesPerWord)); - assert(aligned_to <= aligned_end, "invariant"); - - // for ( ; aligned_to < aligned_end; ++aligned_to) { - // *aligned_to = xvalue; - // } - uintptr_t temp; - __asm__ volatile( - // Unroll loop x8. - " sub %[aend], %[ato], %[temp]\n\t" - " cmp %[temp], 56\n\t" // cc := (aligned_end - aligned_to) > 7 words - " ba %%xcc, 2f\n\t" // goto TEST always - " sub %[aend], 56, %[temp]\n\t" // limit := aligned_end - 7 words - // LOOP: - "1:\n\t" // unrolled x8 store loop top - " cmp %[temp], %[ato]\n\t" // cc := limit > (next) aligned_to - " stx %[xvalue], [%[ato]-64]\n\t" // store 8 words, aligned_to pre-incremented - " stx %[xvalue], [%[ato]-56]\n\t" - " stx %[xvalue], [%[ato]-48]\n\t" - " stx %[xvalue], [%[ato]-40]\n\t" - " stx %[xvalue], [%[ato]-32]\n\t" - " stx %[xvalue], [%[ato]-24]\n\t" - " stx %[xvalue], [%[ato]-16]\n\t" - " stx %[xvalue], [%[ato]-8]\n\t" - // TEST: - "2:\n\t" - " bgu,a %%xcc, 1b\n\t" // goto LOOP if more than 7 words remaining - " add %[ato], 64, %[ato]\n\t" // aligned_to += 8, for next iteration - // Fill remaining < 8 full words. - // Dispatch on (aligned_end - aligned_to). - // offset := (7 - (aligned_end - aligned_to)) + 3 - // 3 instructions from rdpc to DISPATCH - " sub %[ato], %[aend], %[ato]\n\t" // offset := aligned_to - aligned_end - " srax %[ato], 1, %[ato]\n\t" // scale offset for instruction size of 4 - " add %[ato], 40, %[ato]\n\t" // offset += 10 * instruction size - " rd %%pc, %[temp]\n\t" // dispatch on scaled offset - " jmpl %[temp]+%[ato], %%g0\n\t" - " nop\n\t" - // DISPATCH: no direct reference, but without it the store block may be elided. - "3:\n\t" - " stx %[xvalue], [%[aend]-56]\n\t" // aligned_end[-7] = xvalue - " stx %[xvalue], [%[aend]-48]\n\t" - " stx %[xvalue], [%[aend]-40]\n\t" - " stx %[xvalue], [%[aend]-32]\n\t" - " stx %[xvalue], [%[aend]-24]\n\t" - " stx %[xvalue], [%[aend]-16]\n\t" - " stx %[xvalue], [%[aend]-8]\n\t" // aligned_end[-1] = xvalue - : /* only temporaries/overwritten outputs */ - [temp] "=&r" (temp), - [ato] "+&r" (aligned_to) - : [aend] "r" (aligned_end), - [xvalue] "r" (xvalue) - : "cc", "memory"); - to = aligned_end; // setup for suffix - } - // Fill any partial word suffix. Also the prefix if size < BytesPerWord. - fill_subword(to, end, value); -} diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (c) 2008, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "jvm.h" -#include "asm/macroAssembler.inline.hpp" -#include "classfile/javaClasses.inline.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interp_masm.hpp" -#include "logging/log.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" -#include "prims/methodHandles.hpp" -#include "runtime/flags/flagSetting.hpp" -#include "runtime/frame.inline.hpp" -#include "utilities/preserveException.hpp" - -#define __ _masm-> - -#ifdef PRODUCT -#define BLOCK_COMMENT(str) /* nothing */ -#define STOP(error) stop(error) -#else -#define BLOCK_COMMENT(str) __ block_comment(str) -#define STOP(error) block_comment(error); __ stop(error) -#endif - -#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") - -// Workaround for C++ overloading nastiness on '0' for RegisterOrConstant. -static RegisterOrConstant constant(int value) { - return RegisterOrConstant(value); -} - -void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp_reg, Register temp2_reg) { - if (VerifyMethodHandles) - verify_klass(_masm, klass_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_Class), temp_reg, temp2_reg, - "MH argument is a Class"); - __ ld_ptr(Address(klass_reg, java_lang_Class::klass_offset_in_bytes()), klass_reg); -} - -#ifdef ASSERT -static int check_nonzero(const char* xname, int x) { - assert(x != 0, "%s should be nonzero", xname); - return x; -} -#define NONZERO(x) check_nonzero(#x, x) -#else //ASSERT -#define NONZERO(x) (x) -#endif //ASSERT - -#ifdef ASSERT -void MethodHandles::verify_klass(MacroAssembler* _masm, - Register obj_reg, SystemDictionary::WKID klass_id, - Register temp_reg, Register temp2_reg, - const char* error_message) { - InstanceKlass** klass_addr = SystemDictionary::well_known_klass_addr(klass_id); - Klass* klass = SystemDictionary::well_known_klass(klass_id); - bool did_save = false; - if (temp_reg == noreg || temp2_reg == noreg) { - temp_reg = L1; - temp2_reg = L2; - __ save_frame_and_mov(0, obj_reg, L0); - obj_reg = L0; - did_save = true; - } - Label L_ok, L_bad; - BLOCK_COMMENT("verify_klass {"); - __ verify_oop(obj_reg); - __ br_null_short(obj_reg, Assembler::pn, L_bad); - __ load_klass(obj_reg, temp_reg); - __ set(ExternalAddress((Metadata**)klass_addr), temp2_reg); - __ ld_ptr(Address(temp2_reg, 0), temp2_reg); - __ cmp_and_brx_short(temp_reg, temp2_reg, Assembler::equal, Assembler::pt, L_ok); - intptr_t super_check_offset = klass->super_check_offset(); - __ ld_ptr(Address(temp_reg, super_check_offset), temp_reg); - __ set(ExternalAddress((Metadata**)klass_addr), temp2_reg); - __ ld_ptr(Address(temp2_reg, 0), temp2_reg); - __ cmp_and_brx_short(temp_reg, temp2_reg, Assembler::equal, Assembler::pt, L_ok); - __ BIND(L_bad); - if (did_save) __ restore(); - __ STOP(error_message); - __ BIND(L_ok); - if (did_save) __ restore(); - BLOCK_COMMENT("} verify_klass"); -} - -void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) { - Label L; - BLOCK_COMMENT("verify_ref_kind {"); - __ lduw(Address(member_reg, NONZERO(java_lang_invoke_MemberName::flags_offset_in_bytes())), temp); - __ srl( temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_SHIFT, temp); - __ and3(temp, java_lang_invoke_MemberName::MN_REFERENCE_KIND_MASK, temp); - __ cmp_and_br_short(temp, ref_kind, Assembler::equal, Assembler::pt, L); - { char* buf = NEW_C_HEAP_ARRAY(char, 100, mtInternal); - jio_snprintf(buf, 100, "verify_ref_kind expected %x", ref_kind); - if (ref_kind == JVM_REF_invokeVirtual || - ref_kind == JVM_REF_invokeSpecial) - // could do this for all ref_kinds, but would explode assembly code size - trace_method_handle(_masm, buf); - __ STOP(buf); - } - BLOCK_COMMENT("} verify_ref_kind"); - __ bind(L); -} - -#endif // ASSERT - -void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, - bool for_compiler_entry) { - Label L_no_such_method; - assert(method == G5_method, "interpreter calling convention"); - assert_different_registers(method, target, temp); - - 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. - __ verify_thread(); - const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); - __ ld(interp_only, temp); - __ cmp_and_br_short(temp, 0, Assembler::zero, Assembler::pt, run_compiled_code); - // Null method test is replicated below in compiled case, - // it might be able to address across the verify_thread() - __ br_null_short(G5_method, Assembler::pn, L_no_such_method); - __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), target); - __ jmp(target, 0); - __ delayed()->nop(); - __ BIND(run_compiled_code); - // Note: we could fill some delay slots here, but - // it doesn't matter, since this is interpreter code. - } - - // Compiled case, either static or fall-through from runtime conditional - __ br_null_short(G5_method, Assembler::pn, L_no_such_method); - - const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : - Method::from_interpreted_offset(); - __ ld_ptr(G5_method, in_bytes(entry_offset), target); - __ jmp(target, 0); - __ delayed()->nop(); - - __ bind(L_no_such_method); - AddressLiteral ame(StubRoutines::throw_AbstractMethodError_entry()); - __ jump_to(ame, temp); - __ delayed()->nop(); -} - -void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, - Register recv, Register method_temp, - Register temp2, Register temp3, - 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); // temp3 is only passed on - assert(method_temp == G5_method, "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(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), method_temp, temp2); - __ verify_oop(method_temp); - __ load_heap_oop(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2); - __ verify_oop(method_temp); - __ load_heap_oop(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()), method_temp, temp2); - __ verify_oop(method_temp); - __ ld_ptr(Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())), method_temp); - - if (VerifyMethodHandles && !for_compiler_entry) { - // make sure recv is already on stack - __ ld_ptr(method_temp, in_bytes(Method::const_offset()), temp2); - __ load_sized_value(Address(temp2, ConstMethod::size_of_parameters_offset()), - temp2, - sizeof(u2), /*is_signed*/ false); - // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); - Label L; - __ ld_ptr(__ argument_address(temp2, temp2, -1), temp2); - __ cmp_and_br_short(temp2, recv, Assembler::equal, Assembler::pt, L); - __ STOP("receiver not on stack"); - __ BIND(L); - } - - jump_from_method_handle(_masm, method_temp, temp2, temp3, 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. - __ should_not_reach_here(); // empty stubs make SG sick - return NULL; - } - - // I5_savedSP/O5_savedSP: sender SP (must preserve; see prepare_to_jump_from_interpreted) - // G5_method: Method* - // G4 (Gargs): incoming argument list (must preserve) - // O0: used as temp to hold mh or receiver - // O1, O4: garbage temps, blown away - Register O1_scratch = O1; - Register O4_param_size = O4; // size of parameters - - // here's where control starts out: - __ align(CodeEntryAlignment); - address entry_point = __ pc(); - - if (VerifyMethodHandles) { - assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); - - Label L; - BLOCK_COMMENT("verify_intrinsic_id {"); - __ lduh(Address(G5_method, Method::intrinsic_id_offset_in_bytes()), O1_scratch); - __ cmp_and_br_short(O1_scratch, (int) iid, Assembler::equal, Assembler::pt, 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"); - } - __ STOP("bad Method*::intrinsic_id"); - __ bind(L); - BLOCK_COMMENT("} verify_intrinsic_id"); - } - - // First task: Find out how big the argument list is. - Address O4_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)) { - __ ld_ptr(G5_method, in_bytes(Method::const_offset()), O4_param_size); - __ load_sized_value(Address(O4_param_size, ConstMethod::size_of_parameters_offset()), - O4_param_size, - sizeof(u2), /*is_signed*/ false); - // assert(sizeof(u2) == sizeof(Method::_size_of_parameters), ""); - O4_first_arg_addr = __ argument_address(O4_param_size, O4_param_size, -1); - } else { - DEBUG_ONLY(O4_param_size = noreg); - } - - Register O0_mh = noreg; - if (!is_signature_polymorphic_static(iid)) { - __ ld_ptr(O4_first_arg_addr, O0_mh = O0); - DEBUG_ONLY(O4_param_size = noreg); - } - - // O4_first_arg_addr is live! - - if (log_is_enabled(Info, methodhandles)) { - if (O0_mh != noreg) - __ mov(O0_mh, G3_method_handle); // make stub happy - trace_method_handle_interpreter_entry(_masm, iid); - } - - if (iid == vmIntrinsics::_invokeBasic) { - generate_method_handle_dispatch(_masm, iid, O0_mh, noreg, not_for_compiler_entry); - - } else { - // Adjust argument list by popping the trailing MemberName argument. - Register O0_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. - __ ld_ptr(O4_first_arg_addr, O0_recv = O0); - DEBUG_ONLY(O4_param_size = noreg); - } - Register G5_member = G5_method; // MemberName ptr; incoming method ptr is dead now - __ ld_ptr(__ argument_address(constant(0)), G5_member); - __ add(Gargs, Interpreter::stackElementSize, Gargs); - generate_method_handle_dispatch(_masm, iid, O0_recv, G5_member, 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"); - Register temp1 = (for_compiler_entry ? G1_scratch : O1); - Register temp2 = (for_compiler_entry ? G3_scratch : O2); - Register temp3 = (for_compiler_entry ? G4_scratch : O3); - Register temp4 = (for_compiler_entry ? noreg : O4); - if (for_compiler_entry) { - assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : O0), "only valid assignment"); - assert_different_registers(temp1, O0, O1, O2, O3, O4, O5); - assert_different_registers(temp2, O0, O1, O2, O3, O4, O5); - assert_different_registers(temp3, O0, O1, O2, O3, O4, O5); - assert_different_registers(temp4, O0, O1, O2, O3, O4, O5); - } else { - assert_different_registers(temp1, temp2, temp3, temp4, O5_savedSP); // don't trash lastSP - } - if (receiver_reg != noreg) assert_different_registers(temp1, temp2, temp3, temp4, receiver_reg); - if (member_reg != noreg) assert_different_registers(temp1, temp2, temp3, temp4, member_reg); - - if (iid == vmIntrinsics::_invokeBasic) { - // indirect through MH.form.vmentry.vmtarget - jump_to_lambda_form(_masm, receiver_reg, G5_method, temp1, temp2, 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(MemberName_klass), - temp1, temp2, - "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::method_offset_in_bytes())); - Address vmtarget_method( G5_method, NONZERO(java_lang_invoke_ResolvedMethodName::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(receiver_reg, temp1_recv_klass); - __ 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(receiver_reg, temp1_recv_klass); - __ verify_klass_ptr(temp1_recv_klass); - } - if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { - Label L_ok; - Register temp2_defc = temp2; - __ load_heap_oop(member_clazz, temp2_defc, temp3); - load_klass_from_Class(_masm, temp2_defc, temp3, temp4); - __ verify_klass_ptr(temp2_defc); - __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok); - // If we get here, the type check failed! - __ 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 - // O5_savedSP - interpreter linkage (if interpreted) - // O0..O5 - 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, temp2); - } - __ load_heap_oop(member_vmtarget, G5_method, temp3); - __ ld_ptr(vmtarget_method, G5_method); - break; - - case vmIntrinsics::_linkToStatic: - if (VerifyMethodHandles) { - verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp2); - } - __ load_heap_oop(member_vmtarget, G5_method, temp3); - __ ld_ptr(vmtarget_method, G5_method); - 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, temp2); - } - - // pick out the vtable index from the MemberName, and then we can discard it: - Register temp2_index = temp2; - __ ld_ptr(member_vmindex, temp2_index); - - if (VerifyMethodHandles) { - Label L_index_ok; - __ cmp_and_br_short(temp2_index, (int) 0, Assembler::greaterEqual, Assembler::pn, L_index_ok); - __ STOP("no virtual index"); - __ 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, G5_method); - 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, temp2); - } - - Register temp2_intf = temp2; - __ load_heap_oop(member_clazz, temp2_intf, temp3); - load_klass_from_Class(_masm, temp2_intf, temp3, temp4); - __ verify_klass_ptr(temp2_intf); - - Register G5_index = G5_method; - __ ld_ptr(member_vmindex, G5_index); - if (VerifyMethodHandles) { - Label L; - __ cmp_and_br_short(G5_index, 0, Assembler::greaterEqual, Assembler::pt, L); - __ STOP("invalid vtable index for MH.invokeInterface"); - __ bind(L); - } - - // given intf, index, and recv klass, dispatch to the implementation method - __ lookup_interface_method(temp1_recv_klass, temp2_intf, - // note: next two args must be the same: - G5_index, G5_method, - temp3, temp4, - L_incompatible_class_change_error); - break; - } - - default: - fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)); - break; - } - - // Live at this point: - // G5_method - // O5_savedSP (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 rcx_recv be shifted out. - __ verify_method_ptr(G5_method); - jump_from_method_handle(_masm, G5_method, temp1, temp2, for_compiler_entry); - - if (iid == vmIntrinsics::_linkToInterface) { - __ BIND(L_incompatible_class_change_error); - AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); - __ jump_to(icce, temp1); - __ delayed()->nop(); - } - } -} - -#ifndef PRODUCT -void trace_method_handle_stub(const char* adaptername, - oopDesc* mh, - intptr_t* saved_sp, - intptr_t* args, - intptr_t* tracing_fp) { - bool has_mh = (strstr(adaptername, "/static") == NULL && - strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH - const char* mh_reg_name = has_mh ? "G3_mh" : "G3"; - tty->print_cr("MH %s %s=" INTPTR_FORMAT " saved_sp=" INTPTR_FORMAT " args=" INTPTR_FORMAT, - adaptername, mh_reg_name, - p2i(mh), p2i(saved_sp), p2i(args)); - - if (Verbose) { - // dumping last frame with frame::describe - - JavaThread* p = JavaThread::active(); - - ResourceMark rm; - PRESERVE_EXCEPTION_MARK; // may not be needed by safer and unexpensive here - FrameValues values; - - // Note: We want to allow trace_method_handle from any call site. - // While trace_method_handle creates a frame, it may be entered - // without a valid return PC in O7 (e.g. not just after a call). - // Walking that frame could lead to failures due to that invalid PC. - // => carefully detect that frame when doing the stack walking - - // walk up to the right frame using the "tracing_fp" argument - intptr_t* cur_sp = StubRoutines::Sparc::flush_callers_register_windows_func()(); - frame cur_frame(cur_sp, frame::unpatchable, NULL); - - while (cur_frame.fp() != (intptr_t *)(STACK_BIAS+(uintptr_t)tracing_fp)) { - cur_frame = os::get_sender_for_C_frame(&cur_frame); - } - - // safely create a frame and call frame::describe - intptr_t *dump_sp = cur_frame.sender_sp(); - intptr_t *dump_fp = cur_frame.link(); - - bool walkable = has_mh; // whether the traced frame shoud be walkable - - // the sender for cur_frame is the caller of trace_method_handle - if (walkable) { - // The previous definition of walkable may have to be refined - // if new call sites cause the next frame constructor to start - // failing. Alternatively, frame constructors could be - // modified to support the current or future non walkable - // frames (but this is more intrusive and is not considered as - // part of this RFE, which will instead use a simpler output). - frame dump_frame = frame(dump_sp, - cur_frame.sp(), // younger_sp - false); // no adaptation - dump_frame.describe(values, 1); - } else { - // Robust dump for frames which cannot be constructed from sp/younger_sp - // Add descriptions without building a Java frame to avoid issues - values.describe(-1, dump_fp, "fp for #1 "); - values.describe(-1, dump_sp, "sp"); - } - - bool has_args = has_mh; // whether Gargs is meaningful - - // mark args, if seems valid (may not be valid for some adapters) - if (has_args) { - if ((args >= dump_sp) && (args < dump_fp)) { - values.describe(-1, args, "*G4_args"); - } - } - - // mark saved_sp, if seems valid (may not be valid for some adapters) - intptr_t *unbiased_sp = (intptr_t *)(STACK_BIAS+(uintptr_t)saved_sp); - const int ARG_LIMIT = 255, SLOP = 45, UNREASONABLE_STACK_MOVE = (ARG_LIMIT + SLOP); - if ((unbiased_sp >= dump_sp - UNREASONABLE_STACK_MOVE) && (unbiased_sp < dump_fp)) { - values.describe(-1, unbiased_sp, "*saved_sp+STACK_BIAS"); - } - - // Note: the unextended_sp may not be correct - tty->print_cr(" stack layout:"); - values.print(p); - if (has_mh && oopDesc::is_oop(mh)) { - mh->print(); - if (java_lang_invoke_MethodHandle::is_instance(mh)) { - if (java_lang_invoke_MethodHandle::form_offset_in_bytes() != 0) - java_lang_invoke_MethodHandle::form(mh)->print(); - } - } - } -} - -void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { - if (!log_is_enabled(Info, methodhandles)) return; - BLOCK_COMMENT("trace_method_handle {"); - // save: Gargs, O5_savedSP - __ save_frame(16); // need space for saving required FPU state - - __ set((intptr_t) adaptername, O0); - __ mov(G3_method_handle, O1); - __ mov(I5_savedSP, O2); - __ mov(Gargs, O3); - __ mov(I6, O4); // frame identifier for safe stack walking - - // Save scratched registers that might be needed. Robustness is more - // important than optimizing the saves for this debug only code. - - // save FP result, valid at some call sites (adapter_opt_return_float, ...) - Address d_save(FP, -sizeof(jdouble) + STACK_BIAS); - __ stf(FloatRegisterImpl::D, Ftos_d, d_save); - // Safely save all globals but G2 (handled by call_VM_leaf) and G7 - // (OS reserved). - __ mov(G3_method_handle, L3); - __ mov(Gargs, L4); - __ mov(G5_method_type, L5); - __ mov(G6, L6); - __ mov(G1, L1); - - __ call_VM_leaf(L2 /* for G2 */, CAST_FROM_FN_PTR(address, trace_method_handle_stub)); - - __ mov(L3, G3_method_handle); - __ mov(L4, Gargs); - __ mov(L5, G5_method_type); - __ mov(L6, G6); - __ mov(L1, G1); - __ ldf(FloatRegisterImpl::D, d_save, Ftos_d); - - __ restore(); - BLOCK_COMMENT("} trace_method_handle"); -} -#endif // PRODUCT diff --git a/src/hotspot/cpu/sparc/methodHandles_sparc.hpp b/src/hotspot/cpu/sparc/methodHandles_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/methodHandles_sparc.hpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2011, 2017, 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. - * - */ - -// Platform-specific definitions for method handles. -// These definitions are inlined into class MethodHandles. - -// Adapters -enum /* platform_dependent_constants */ { - adapter_code_size = 35000 DEBUG_ONLY(+ 50000) -}; - -// Additional helper methods for MethodHandles code generation: -public: - static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg, Register temp_reg, Register temp2_reg); - - static void verify_klass(MacroAssembler* _masm, - Register obj_reg, SystemDictionary::WKID klass_id, - Register temp_reg, Register temp2_reg, - const char* error_message = "wrong klass") NOT_DEBUG_RETURN; - - static void verify_method_handle(MacroAssembler* _masm, Register mh_reg, - Register temp_reg, Register temp2_reg) { - verify_klass(_masm, mh_reg, SystemDictionary::WK_KLASS_ENUM_NAME(java_lang_invoke_MethodHandle), - temp_reg, temp2_reg, - "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, Register temp2, - bool for_compiler_entry); - - static void jump_to_lambda_form(MacroAssembler* _masm, - Register recv, Register method_temp, - Register temp2, Register temp3, - bool for_compiler_entry); diff --git a/src/hotspot/cpu/sparc/nativeInst_sparc.cpp b/src/hotspot/cpu/sparc/nativeInst_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/nativeInst_sparc.cpp +++ /dev/null @@ -1,912 +0,0 @@ -/* - * Copyright (c) 1997, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeCache.hpp" -#include "code/compiledIC.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_sparc.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 NativeInstruction::set_data64_sethi(address instaddr, intptr_t x) { - ResourceMark rm; - CodeBuffer buf(instaddr, 10 * BytesPerInstWord ); - MacroAssembler* _masm = new MacroAssembler(&buf); - Register destreg; - - destreg = inv_rd(*(unsigned int *)instaddr); - // Generate a the new sequence - _masm->patchable_sethi(x, destreg); - ICache::invalidate_range(instaddr, 7 * BytesPerInstWord); -} - -void NativeInstruction::verify_data64_sethi(address instaddr, intptr_t x) { - ResourceMark rm; - unsigned char buffer[10 * BytesPerInstWord]; - CodeBuffer buf(buffer, 10 * BytesPerInstWord); - MacroAssembler masm(&buf); - - Register destreg = inv_rd(*(unsigned int *)instaddr); - // Generate the proper sequence into a temporary buffer and compare - // it with the original sequence. - masm.patchable_sethi(x, destreg); - int len = buffer - masm.pc(); - for (int i = 0; i < len; i++) { - guarantee(instaddr[i] == buffer[i], "instructions must match"); - } -} - -void NativeInstruction::verify() { - // make sure code pattern is actually an instruction address - address addr = addr_at(0); - if (addr == 0 || ((intptr_t)addr & 3) != 0) { - fatal("not an instruction address"); - } -} - -void NativeInstruction::print() { - tty->print_cr(INTPTR_FORMAT ": 0x%x", p2i(addr_at(0)), long_at(0)); -} - -void NativeInstruction::set_long_at(int offset, int i) { - address addr = addr_at(offset); - *(int*)addr = i; - ICache::invalidate_word(addr); -} - -void NativeInstruction::set_jlong_at(int offset, jlong i) { - address addr = addr_at(offset); - *(jlong*)addr = i; - // Don't need to invalidate 2 words here, because - // the flush instruction operates on doublewords. - ICache::invalidate_word(addr); -} - -void NativeInstruction::set_addr_at(int offset, address x) { - address addr = addr_at(offset); - assert( ((intptr_t)addr & (wordSize-1)) == 0, "set_addr_at bad address alignment"); - *(uintptr_t*)addr = (uintptr_t)x; - // Don't need to invalidate 2 words here in the 64-bit case, - // because the flush instruction operates on doublewords. - ICache::invalidate_word(addr); - // The Intel code has this assertion for NativeCall::set_destination, - // NativeMovConstReg::set_data, NativeMovRegMem::set_offset, - // NativeJump::set_jump_destination, and NativePushImm32::set_data - //assert (Patching_lock->owned_by_self(), "must hold lock to patch instruction") -} - -bool NativeInstruction::is_zero_test(Register ®) { - int x = long_at(0); - Assembler::op3s temp = (Assembler::op3s) (Assembler::sub_op3 | Assembler::cc_bit_op3); - if (is_op3(x, temp, Assembler::arith_op) && - inv_immed(x) && inv_rd(x) == G0) { - if (inv_rs1(x) == G0) { - reg = inv_rs2(x); - return true; - } else if (inv_rs2(x) == G0) { - reg = inv_rs1(x); - return true; - } - } - return false; -} - -bool NativeInstruction::is_load_store_with_small_offset(Register reg) { - int x = long_at(0); - if (is_op(x, Assembler::ldst_op) && - inv_rs1(x) == reg && inv_immed(x)) { - return true; - } - return false; -} - -void NativeCall::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a call instruction - int x = long_at(0); - if (!is_op(x, Assembler::call_op)) { - fatal("not a call: 0x%x @ " INTPTR_FORMAT, x, p2i(instruction_address())); - } -} - -void NativeCall::print() { - tty->print_cr(INTPTR_FORMAT ": call " INTPTR_FORMAT, p2i(instruction_address()), p2i(destination())); -} - - -// MT-safe patching of a call instruction (and following word). -// First patches the second word, and then atomicly replaces -// the first word with the first new instruction word. -// Other processors might briefly see the old first word -// followed by the new second word. This is OK if the old -// second word is harmless, and the new second word may be -// harmlessly executed in the delay slot of the call. -void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { - assert(Patching_lock->is_locked() || - SafepointSynchronize::is_at_safepoint(), "concurrent code patching"); - assert (instr_addr != NULL, "illegal address for code patching"); - NativeCall* n_call = nativeCall_at (instr_addr); // checking that it is a call - assert(NativeCall::instruction_size == 8, "wrong instruction size; must be 8"); - int i0 = ((int*)code_buffer)[0]; - int i1 = ((int*)code_buffer)[1]; - int* contention_addr = (int*) n_call->addr_at(1*BytesPerInstWord); - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); - // The set_long_at calls do the ICacheInvalidate so we just need to do them in reverse order - n_call->set_long_at(1*BytesPerInstWord, i1); - n_call->set_long_at(0*BytesPerInstWord, i0); - // NOTE: It is possible that another thread T will execute - // only the second patched word. - // In other words, since the original instruction is this - // call patching_stub; nop (NativeCall) - // and the new sequence from the buffer is this: - // sethi %hi(K), %r; add %r, %lo(K), %r (NativeMovConstReg) - // what T will execute is this: - // call patching_stub; add %r, %lo(K), %r - // thereby putting garbage into %r before calling the patching stub. - // This is OK, because the patching stub ignores the value of %r. - - // Make sure the first-patched instruction, which may co-exist - // briefly with the call, will do something harmless. - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); -} - -// 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. Thus, the displacement field must be -// instruction-word-aligned. This is always true on SPARC. -// -// Used in the runtime linkage of calls; see class CompiledIC. -void NativeCall::set_destination_mt_safe(address dest) { - assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || - CompiledICLocker::is_safe(addr_at(0)), - "concurrent code patching"); - // set_destination uses set_long_at which does the ICache::invalidate - set_destination(dest); -} - -// Code for unit testing implementation of NativeCall class -void NativeCall::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeCall *nc; - uint idx; - int offsets[] = { - 0x0, - (int)0xfffffff0, - (int)0x7ffffff0, - (int)0x80000000, - 0x20, - 0x4000, - }; - - VM_Version::allow_all(); - - a->call( a->pc(), relocInfo::none ); - a->delayed()->nop(); - nc = nativeCall_at( cb.insts_begin() ); - nc->print(); - - nc = nativeCall_overwriting_at( nc->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nc->set_destination( cb.insts_begin() + offsets[idx] ); - assert(nc->destination() == (cb.insts_begin() + offsets[idx]), "check unit test"); - nc->print(); - } - - nc = nativeCall_before( cb.insts_begin() + 8 ); - nc->print(); - - VM_Version::revert(); -#endif -} -// End code for unit testing implementation of NativeCall class - -//------------------------------------------------------------------- - -void NativeFarCall::set_destination(address dest) { - // Address materialized in the instruction stream, so nothing to do. - return; -#if 0 // What we'd do if we really did want to change the destination - if (destination() == dest) { - return; - } - ResourceMark rm; - CodeBuffer buf(addr_at(0), instruction_size + 1); - MacroAssembler* _masm = new MacroAssembler(&buf); - // Generate the new sequence - AddressLiteral(dest); - _masm->jumpl_to(dest, O7, O7); - ICache::invalidate_range(addr_at(0), instruction_size ); -#endif -} - -void NativeFarCall::verify() { - // make sure code pattern is actually a jumpl_to instruction - assert((int)instruction_size == (int)NativeJump::instruction_size, "same as jump_to"); - assert((int)jmpl_offset == (int)NativeMovConstReg::add_offset, "sethi size ok"); - nativeJump_at(addr_at(0))->verify(); -} - -bool NativeFarCall::is_call_at(address instr) { - return nativeInstruction_at(instr)->is_sethi(); -} - -void NativeFarCall::print() { - tty->print_cr(INTPTR_FORMAT ": call " INTPTR_FORMAT, p2i(instruction_address()), p2i(destination())); -} - -bool NativeFarCall::destination_is_compiled_verified_entry_point() { - nmethod* callee = CodeCache::find_nmethod(destination()); - if (callee == NULL) { - return false; - } else { - return destination() == callee->verified_entry_point(); - } -} - -// MT-safe patching of a far call. -void NativeFarCall::replace_mt_safe(address instr_addr, address code_buffer) { - Unimplemented(); -} - -// Code for unit testing implementation of NativeFarCall class -void NativeFarCall::test() { - Unimplemented(); -} -// End code for unit testing implementation of NativeFarCall class - -//------------------------------------------------------------------- - - -void NativeMovConstReg::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a "set_metadata" synthetic instruction - // see MacroAssembler::set_oop() - int i0 = long_at(sethi_offset); - int i1 = long_at(add_offset); - - // verify the pattern "sethi %hi22(imm), reg ; add reg, %lo10(imm), reg" - Register rd = inv_rd(i0); - if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) { - fatal("not a set_metadata"); - } -} - - -void NativeMovConstReg::print() { - tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data()); -} - - -intptr_t NativeMovConstReg::data() const { - return data64(addr_at(sethi_offset), long_at(add_offset)); -} - - -void NativeMovConstReg::set_data(intptr_t x) { - set_data64_sethi(addr_at(sethi_offset), x); - set_long_at(add_offset, set_data32_simm13( long_at(add_offset), x)); - - // also store the value into an oop_Relocation cell, if any - CodeBlob* cb = CodeCache::find_blob(instruction_address()); - nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; - if (nm != NULL) { - RelocIterator iter(nm, instruction_address(), next_instruction_address()); - oop* oop_addr = NULL; - Metadata** metadata_addr = NULL; - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation *r = iter.oop_reloc(); - if (oop_addr == NULL) { - oop_addr = r->oop_addr(); - *oop_addr = cast_to_oop(x); - } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } - } - if (iter.type() == relocInfo::metadata_type) { - metadata_Relocation *r = iter.metadata_reloc(); - if (metadata_addr == NULL) { - metadata_addr = r->metadata_addr(); - *metadata_addr = (Metadata*)x; - } else { - assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); - } - } - } - } -} - - -// Code for unit testing implementation of NativeMovConstReg class -void NativeMovConstReg::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeMovConstReg* nm; - uint idx; - int offsets[] = { - 0x0, - (int)0x7fffffff, - (int)0x80000000, - (int)0xffffffff, - 0x20, - 4096, - 4097, - }; - - VM_Version::allow_all(); - - AddressLiteral al1(0xaaaabbbb, relocInfo::external_word_type); - a->sethi(al1, I3); - a->add(I3, al1.low10(), I3); - AddressLiteral al2(0xccccdddd, relocInfo::external_word_type); - a->sethi(al2, O2); - a->add(O2, al2.low10(), O2); - - nm = nativeMovConstReg_at( cb.insts_begin() ); - nm->print(); - - nm = nativeMovConstReg_at( nm->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nm->set_data( offsets[idx] ); - assert(nm->data() == offsets[idx], "check unit test"); - } - nm->print(); - - VM_Version::revert(); -#endif -} -// End code for unit testing implementation of NativeMovConstReg class - -//------------------------------------------------------------------- - -void NativeMovConstReg32::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a "set_metadata" synthetic instruction - // see MacroAssembler::set_oop() - int i0 = long_at(sethi_offset); - int i1 = long_at(add_offset); - - // verify the pattern "sethi %hi22(imm), reg ; add reg, %lo10(imm), reg" - Register rd = inv_rd(i0); - if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) { - fatal("not a set_metadata"); - } -} - - -void NativeMovConstReg32::print() { - tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data()); -} - - -intptr_t NativeMovConstReg32::data() const { - return data32(long_at(sethi_offset), long_at(add_offset)); -} - - -void NativeMovConstReg32::set_data(intptr_t x) { - set_long_at(sethi_offset, set_data32_sethi( long_at(sethi_offset), x)); - set_long_at(add_offset, set_data32_simm13( long_at(add_offset), x)); - - // also store the value into an oop_Relocation cell, if any - CodeBlob* cb = CodeCache::find_blob(instruction_address()); - nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; - if (nm != NULL) { - RelocIterator iter(nm, instruction_address(), next_instruction_address()); - oop* oop_addr = NULL; - Metadata** metadata_addr = NULL; - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation *r = iter.oop_reloc(); - if (oop_addr == NULL) { - oop_addr = r->oop_addr(); - *oop_addr = cast_to_oop(x); - } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } - } - if (iter.type() == relocInfo::metadata_type) { - metadata_Relocation *r = iter.metadata_reloc(); - if (metadata_addr == NULL) { - metadata_addr = r->metadata_addr(); - *metadata_addr = (Metadata*)x; - } else { - assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); - } - } - } - } -} - -//------------------------------------------------------------------- - -void NativeMovConstRegPatching::verify() { - NativeInstruction::verify(); - // Make sure code pattern is sethi/nop/add. - int i0 = long_at(sethi_offset); - int i1 = long_at(nop_offset); - int i2 = long_at(add_offset); - assert((int)nop_offset == (int)NativeMovConstReg::add_offset, "sethi size ok"); - - // Verify the pattern "sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg" - // The casual reader should note that on Sparc a nop is a special case if sethi - // in which the destination register is %g0. - Register rd0 = inv_rd(i0); - Register rd1 = inv_rd(i1); - if (!(is_op2(i0, Assembler::sethi_op2) && rd0 != G0 && - is_op2(i1, Assembler::sethi_op2) && rd1 == G0 && // nop is a special case of sethi - is_op3(i2, Assembler::add_op3, Assembler::arith_op) && - inv_immed(i2) && (unsigned)get_simm13(i2) < (1 << 10) && - rd0 == inv_rs1(i2) && rd0 == inv_rd(i2))) { - fatal("not a set_metadata"); - } -} - - -void NativeMovConstRegPatching::print() { - tty->print_cr(INTPTR_FORMAT ": mov reg, 0x%x", p2i(instruction_address()), data()); -} - - -int NativeMovConstRegPatching::data() const { - return data64(addr_at(sethi_offset), long_at(add_offset)); -} - - -void NativeMovConstRegPatching::set_data(int x) { - set_data64_sethi(addr_at(sethi_offset), x); - set_long_at(add_offset, set_data32_simm13(long_at(add_offset), x)); - - // also store the value into an oop_Relocation cell, if any - CodeBlob* cb = CodeCache::find_blob(instruction_address()); - nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; - if (nm != NULL) { - RelocIterator iter(nm, instruction_address(), next_instruction_address()); - oop* oop_addr = NULL; - Metadata** metadata_addr = NULL; - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation *r = iter.oop_reloc(); - if (oop_addr == NULL) { - oop_addr = r->oop_addr(); - *oop_addr = cast_to_oop(x); - } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } - } - if (iter.type() == relocInfo::metadata_type) { - metadata_Relocation *r = iter.metadata_reloc(); - if (metadata_addr == NULL) { - metadata_addr = r->metadata_addr(); - *metadata_addr = (Metadata*)x; - } else { - assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); - } - } - } - } -} - - -// Code for unit testing implementation of NativeMovConstRegPatching class -void NativeMovConstRegPatching::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeMovConstRegPatching* nm; - uint idx; - int offsets[] = { - 0x0, - (int)0x7fffffff, - (int)0x80000000, - (int)0xffffffff, - 0x20, - 4096, - 4097, - }; - - VM_Version::allow_all(); - - AddressLiteral al1(0xaaaabbbb, relocInfo::external_word_type); - a->sethi(al1, I3); - a->nop(); - a->add(I3, al1.low10(), I3); - AddressLiteral al2(0xccccdddd, relocInfo::external_word_type); - a->sethi(al2, O2); - a->nop(); - a->add(O2, al2.low10(), O2); - - nm = nativeMovConstRegPatching_at( cb.insts_begin() ); - nm->print(); - - nm = nativeMovConstRegPatching_at( nm->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nm->set_data( offsets[idx] ); - assert(nm->data() == offsets[idx], "check unit test"); - } - nm->print(); - - VM_Version::revert(); -#endif // ASSERT -} -// End code for unit testing implementation of NativeMovConstRegPatching class - - -//------------------------------------------------------------------- - - -void NativeMovRegMem::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a "ld" or "st" of some sort. - int i0 = long_at(0); - int op3 = inv_op3(i0); - - assert((int)add_offset == NativeMovConstReg::add_offset, "sethi size ok"); - - if (!(is_op(i0, Assembler::ldst_op) && - inv_immed(i0) && - 0 != (op3 < op3_ldst_int_limit - ? (1 << op3 ) & (op3_mask_ld | op3_mask_st) - : (1 << (op3 - op3_ldst_int_limit)) & (op3_mask_ldf | op3_mask_stf)))) - { - int i1 = long_at(ldst_offset); - Register rd = inv_rd(i0); - - op3 = inv_op3(i1); - if (!is_op(i1, Assembler::ldst_op) && rd == inv_rs2(i1) && - 0 != (op3 < op3_ldst_int_limit - ? (1 << op3 ) & (op3_mask_ld | op3_mask_st) - : (1 << (op3 - op3_ldst_int_limit)) & (op3_mask_ldf | op3_mask_stf))) { - fatal("not a ld* or st* op"); - } - } -} - - -void NativeMovRegMem::print() { - if (is_immediate()) { - // offset is a signed 13-bit immediate, so casting it to int will not lose significant bits - tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + %d]", p2i(instruction_address()), (int)offset()); - } else { - tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + reg]", p2i(instruction_address())); - } -} - - -// Code for unit testing implementation of NativeMovRegMem class -void NativeMovRegMem::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 1000, 1000); - MacroAssembler* a = new MacroAssembler(&cb); - NativeMovRegMem* nm; - uint idx = 0; - uint idx1; - int offsets[] = { - 0x0, - (int)0xffffffff, - (int)0x7fffffff, - (int)0x80000000, - 4096, - 4097, - 0x20, - 0x4000, - }; - - VM_Version::allow_all(); - - AddressLiteral al1(0xffffffff, relocInfo::external_word_type); - AddressLiteral al2(0xaaaabbbb, relocInfo::external_word_type); - a->ldsw( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldsw( G5, I3, G4 ); idx++; - a->ldsb( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldsb( G5, I3, G4 ); idx++; - a->ldsh( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldsh( G5, I3, G4 ); idx++; - a->lduw( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->lduw( G5, I3, G4 ); idx++; - a->ldub( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldub( G5, I3, G4 ); idx++; - a->lduh( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->lduh( G5, I3, G4 ); idx++; - a->ldx( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldx( G5, I3, G4 ); idx++; - a->ldd( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldd( G5, I3, G4 ); idx++; - a->ldf( FloatRegisterImpl::D, O2, -1, F14 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldf( FloatRegisterImpl::S, O0, I3, F15 ); idx++; - - a->stw( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stw( G5, G4, I3 ); idx++; - a->stb( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stb( G5, G4, I3 ); idx++; - a->sth( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->sth( G5, G4, I3 ); idx++; - a->stx( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stx( G5, G4, I3 ); idx++; - a->std( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->std( G5, G4, I3 ); idx++; - a->stf( FloatRegisterImpl::S, F18, O2, -1 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stf( FloatRegisterImpl::S, F15, O0, I3 ); idx++; - - nm = nativeMovRegMem_at( cb.insts_begin() ); - nm->print(); - nm->set_offset( low10(0) ); - nm->print(); - nm->add_offset_in_bytes( low10(0xbb) * wordSize ); - nm->print(); - - while (--idx) { - nm = nativeMovRegMem_at( nm->next_instruction_address() ); - nm->print(); - for (idx1 = 0; idx1 < ARRAY_SIZE(offsets); idx1++) { - nm->set_offset( nm->is_immediate() ? low10(offsets[idx1]) : offsets[idx1] ); - assert(nm->offset() == (nm->is_immediate() ? low10(offsets[idx1]) : offsets[idx1]), - "check unit test"); - nm->print(); - } - nm->add_offset_in_bytes( low10(0xbb) * wordSize ); - nm->print(); - } - - VM_Version::revert(); -#endif // ASSERT -} - -// End code for unit testing implementation of NativeMovRegMem class - - -//-------------------------------------------------------------------------------- - - -void NativeJump::verify() { - NativeInstruction::verify(); - int i0 = long_at(sethi_offset); - int i1 = long_at(jmpl_offset); - assert((int)jmpl_offset == (int)NativeMovConstReg::add_offset, "sethi size ok"); - // verify the pattern "sethi %hi22(imm), treg ; jmpl treg, %lo10(imm), lreg" - Register rd = inv_rd(i0); - // In LP64, the jump instruction location varies for non relocatable - // jumps, for example is could be sethi, xor, jmp instead of the - // 7 instructions for sethi. So let's check sethi only. - if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) { - fatal("not a jump_to instruction"); - } -} - - -void NativeJump::print() { - tty->print_cr(INTPTR_FORMAT ": jmpl reg, " INTPTR_FORMAT, p2i(instruction_address()), p2i(jump_destination())); -} - - -// Code for unit testing implementation of NativeJump class -void NativeJump::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeJump* nj; - uint idx; - int offsets[] = { - 0x0, - (int)0xffffffff, - (int)0x7fffffff, - (int)0x80000000, - 4096, - 4097, - 0x20, - 0x4000, - }; - - VM_Version::allow_all(); - - AddressLiteral al(0x7fffbbbb, relocInfo::external_word_type); - a->sethi(al, I3); - a->jmpl(I3, al.low10(), G0, RelocationHolder::none); - a->delayed()->nop(); - a->sethi(al, I3); - a->jmpl(I3, al.low10(), L3, RelocationHolder::none); - a->delayed()->nop(); - - nj = nativeJump_at( cb.insts_begin() ); - nj->print(); - - nj = nativeJump_at( nj->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nj->set_jump_destination( nj->instruction_address() + offsets[idx] ); - assert(nj->jump_destination() == (nj->instruction_address() + offsets[idx]), "check unit test"); - nj->print(); - } - - VM_Version::revert(); -#endif // ASSERT -} -// End code for unit testing implementation of NativeJump class - - -void NativeJump::insert(address code_pos, address entry) { - Unimplemented(); -} - -// MT safe inserting of a jump over an unknown instruction sequence (used by nmethod::makeZombie) -// The problem: jump_to is a 3-word instruction (including its delay slot). -// Atomic write can be only with 1 word. -void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { - // Here's one way to do it: Pre-allocate a three-word jump sequence somewhere - // in the header of the nmethod, within a short branch's span of the patch point. - // Set up the jump sequence using NativeJump::insert, and then use an annulled - // unconditional branch at the target site (an atomic 1-word update). - // Limitations: You can only patch nmethods, with any given nmethod patched at - // most once, and the patch must be in the nmethod's header. - // It's messy, but you can ask the CodeCache for the nmethod containing the - // target address. - - // %%%%% For now, do something MT-stupid: - ResourceMark rm; - int code_size = 1 * BytesPerInstWord; - CodeBuffer cb(verified_entry, code_size + 1); - MacroAssembler* a = new MacroAssembler(&cb); - a->ldsw(G0, 0, O7); // "ld" must agree with code in the signal handler - ICache::invalidate_range(verified_entry, code_size); -} - - -void NativeIllegalInstruction::insert(address code_pos) { - NativeIllegalInstruction* nii = (NativeIllegalInstruction*) nativeInstruction_at(code_pos); - nii->set_long_at(0, illegal_instruction()); -} - -static int illegal_instruction_bits = 0; - -int NativeInstruction::illegal_instruction() { - if (illegal_instruction_bits == 0) { - ResourceMark rm; - char buf[40]; - CodeBuffer cbuf((address)&buf[0], 20); - MacroAssembler* a = new MacroAssembler(&cbuf); - address ia = a->pc(); - a->trap(ST_RESERVED_FOR_USER_0 + 1); - int bits = *(int*)ia; - assert(is_op3(bits, Assembler::trap_op3, Assembler::arith_op), "bad instruction"); - illegal_instruction_bits = bits; - assert(illegal_instruction_bits != 0, "oops"); - } - return illegal_instruction_bits; -} - -static int ic_miss_trap_bits = 0; - -bool NativeInstruction::is_ic_miss_trap() { - if (ic_miss_trap_bits == 0) { - ResourceMark rm; - char buf[40]; - CodeBuffer cbuf((address)&buf[0], 20); - MacroAssembler* a = new MacroAssembler(&cbuf); - address ia = a->pc(); - a->trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0 + 2); - int bits = *(int*)ia; - assert(is_op3(bits, Assembler::trap_op3, Assembler::arith_op), "bad instruction"); - ic_miss_trap_bits = bits; - assert(ic_miss_trap_bits != 0, "oops"); - } - return long_at(0) == ic_miss_trap_bits; -} - - -bool NativeInstruction::is_illegal() { - if (illegal_instruction_bits == 0) { - return false; - } - return long_at(0) == illegal_instruction_bits; -} - - -void NativeGeneralJump::verify() { - assert(((NativeInstruction *)this)->is_jump() || - ((NativeInstruction *)this)->is_cond_jump(), "not a general jump instruction"); -} - - -void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { - Assembler::Condition condition = Assembler::always; - int x = Assembler::op2(Assembler::br_op2) | Assembler::annul(false) | - Assembler::cond(condition) | Assembler::wdisp((intptr_t)entry, (intptr_t)code_pos, 22); - NativeGeneralJump* ni = (NativeGeneralJump*) nativeInstruction_at(code_pos); - ni->set_long_at(0, x); -} - - -// MT-safe patching of a jmp instruction (and following word). -// First patches the second word, and then atomicly replaces -// the first word with the first new instruction word. -// Other processors might briefly see the old first word -// followed by the new second word. This is OK if the old -// second word is harmless, and the new second word may be -// harmlessly executed in the delay slot of the call. -void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { - assert(Patching_lock->is_locked() || - SafepointSynchronize::is_at_safepoint(), "concurrent code patching"); - assert (instr_addr != NULL, "illegal address for code patching"); - NativeGeneralJump* h_jump = nativeGeneralJump_at (instr_addr); // checking that it is a call - assert(NativeGeneralJump::instruction_size == 8, "wrong instruction size; must be 8"); - int i0 = ((int*)code_buffer)[0]; - int i1 = ((int*)code_buffer)[1]; - int* contention_addr = (int*) h_jump->addr_at(1*BytesPerInstWord); - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); - // The set_long_at calls do the ICacheInvalidate so we just need to do them in reverse order - h_jump->set_long_at(1*BytesPerInstWord, i1); - h_jump->set_long_at(0*BytesPerInstWord, i0); - // NOTE: It is possible that another thread T will execute - // only the second patched word. - // In other words, since the original instruction is this - // jmp patching_stub; nop (NativeGeneralJump) - // and the new sequence from the buffer is this: - // sethi %hi(K), %r; add %r, %lo(K), %r (NativeMovConstReg) - // what T will execute is this: - // jmp patching_stub; add %r, %lo(K), %r - // thereby putting garbage into %r before calling the patching stub. - // This is OK, because the patching stub ignores the value of %r. - - // Make sure the first-patched instruction, which may co-exist - // briefly with the call, will do something harmless. - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); -} diff --git a/src/hotspot/cpu/sparc/nativeInst_sparc.hpp b/src/hotspot/cpu/sparc/nativeInst_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/nativeInst_sparc.hpp +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_NATIVEINST_SPARC_HPP -#define CPU_SPARC_NATIVEINST_SPARC_HPP - -#include "asm/macroAssembler.hpp" -#include "runtime/icache.hpp" -#include "runtime/os.hpp" - -// We have interface for the following instructions: -// - NativeInstruction -// - - NativeCall -// - - NativeFarCall -// - - NativeMovConstReg -// - - NativeMovConstRegPatching -// - - NativeMovRegMem -// - - NativeJump -// - - NativeGeneralJump -// - - NativeIllegalInstruction -// The base class for different kinds of native instruction abstractions. -// Provides the primitive operations to manipulate code relative to this. -class NativeInstruction { - friend class Relocation; - - public: - enum Sparc_specific_constants { - nop_instruction_size = 4 - }; - - bool is_nop() { return long_at(0) == nop_instruction(); } - bool is_call() { return is_op(long_at(0), Assembler::call_op); } - bool is_call_reg() { return is_op(long_at(0), Assembler::arith_op); } - bool is_sethi() { return (is_op2(long_at(0), Assembler::sethi_op2) - && inv_rd(long_at(0)) != G0); } - - bool sets_cc() { - // conservative (returns true for some instructions that do not set the - // the condition code, such as, "save". - // Does not return true for the deprecated tagged instructions, such as, TADDcc - int x = long_at(0); - return (is_op(x, Assembler::arith_op) && - (inv_op3(x) & Assembler::cc_bit_op3) == Assembler::cc_bit_op3); - } - bool is_illegal(); - bool is_zombie() { - int x = long_at(0); - return (is_op3(x, Assembler::ldsw_op3, Assembler::ldst_op) && - inv_rs1(x) == G0 && inv_rd(x) == O7); - } - bool is_ic_miss_trap(); // Inline-cache uses a trap to detect a miss - bool is_return() { - // is it the output of MacroAssembler::ret or MacroAssembler::retl? - int x = long_at(0); - const int pc_return_offset = 8; // see frame_sparc.hpp - return is_op3(x, Assembler::jmpl_op3, Assembler::arith_op) - && (inv_rs1(x) == I7 || inv_rs1(x) == O7) - && inv_immed(x) && inv_simm(x, 13) == pc_return_offset - && inv_rd(x) == G0; - } - bool is_int_jump() { - // is it the output of MacroAssembler::b? - int x = long_at(0); - return is_op2(x, Assembler::bp_op2) || is_op2(x, Assembler::br_op2); - } - bool is_float_jump() { - // is it the output of MacroAssembler::fb? - int x = long_at(0); - return is_op2(x, Assembler::fbp_op2) || is_op2(x, Assembler::fb_op2); - } - bool is_jump() { - return is_int_jump() || is_float_jump(); - } - bool is_cond_jump() { - int x = long_at(0); - return (is_int_jump() && Assembler::inv_cond(x) != Assembler::always) || - (is_float_jump() && Assembler::inv_cond(x) != Assembler::f_always); - } - - bool is_stack_bang() { - int x = long_at(0); - return is_op3(x, Assembler::stw_op3, Assembler::ldst_op) && - (inv_rd(x) == G0) && (inv_rs1(x) == SP) && (inv_rs2(x) == G3_scratch); - } - - bool is_prefetch() { - int x = long_at(0); - return is_op3(x, Assembler::prefetch_op3, Assembler::ldst_op); - } - - bool is_membar() { - int x = long_at(0); - return is_op3(x, Assembler::membar_op3, Assembler::arith_op) && - (inv_rd(x) == G0) && (inv_rs1(x) == O7); - } - - bool is_safepoint_poll() { - int x = long_at(0); - return is_op3(x, Assembler::ldx_op3, Assembler::ldst_op) && - (inv_rd(x) == G0) && (inv_immed(x) ? Assembler::inv_simm13(x) == 0 : inv_rs2(x) == G0); - } - - bool is_zero_test(Register ®); - bool is_load_store_with_small_offset(Register reg); - - public: - static int nop_instruction() { return Assembler::op(Assembler::branch_op) | Assembler::op2(Assembler::sethi_op2); } - static int illegal_instruction(); // the output of __ breakpoint_trap() - static int call_instruction(address destination, address pc) { return Assembler::op(Assembler::call_op) | Assembler::wdisp((intptr_t)destination, (intptr_t)pc, 30); } - -protected: - address addr_at(int offset) const { return address(this) + offset; } - int long_at(int offset) const { return *(int*)addr_at(offset); } - void set_long_at(int offset, int i); /* deals with I-cache */ - void set_jlong_at(int offset, jlong i); /* deals with I-cache */ - void set_addr_at(int offset, address x); /* deals with I-cache */ - - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(BytesPerInstWord); } - - static bool is_op( int x, Assembler::ops opval) { - return Assembler::inv_op(x) == opval; - } - static bool is_op2(int x, Assembler::op2s op2val) { - return Assembler::inv_op(x) == Assembler::branch_op && Assembler::inv_op2(x) == op2val; - } - static bool is_op3(int x, Assembler::op3s op3val, Assembler::ops opval) { - return Assembler::inv_op(x) == opval && Assembler::inv_op3(x) == op3val; - } - - // utilities to help subclasses decode: - static Register inv_rd( int x ) { return Assembler::inv_rd( x); } - static Register inv_rs1( int x ) { return Assembler::inv_rs1(x); } - static Register inv_rs2( int x ) { return Assembler::inv_rs2(x); } - - static bool inv_immed( int x ) { return Assembler::inv_immed(x); } - static bool inv_annul( int x ) { return (Assembler::annul(true) & x) != 0; } - static int inv_cond( int x ) { return Assembler::inv_cond(x); } - - static int inv_op( int x ) { return Assembler::inv_op( x); } - static int inv_op2( int x ) { return Assembler::inv_op2(x); } - static int inv_op3( int x ) { return Assembler::inv_op3(x); } - - static int inv_simm( int x, int nbits ) { return Assembler::inv_simm(x, nbits); } - static intptr_t inv_wdisp( int x, int nbits ) { return Assembler::inv_wdisp( x, 0, nbits); } - static intptr_t inv_wdisp16( int x ) { return Assembler::inv_wdisp16(x, 0); } - static int branch_destination_offset(int x) { return MacroAssembler::branch_destination(x, 0); } - static int patch_branch_destination_offset(int dest_offset, int x) { - return MacroAssembler::patched_branch(dest_offset, x, 0); - } - - // utility for checking if x is either of 2 small constants - static bool is_either(int x, int k1, int k2) { - // return x == k1 || x == k2; - return (1 << x) & (1 << k1 | 1 << k2); - } - - // utility for checking overflow of signed instruction fields - static bool fits_in_simm(int x, int nbits) { - // cf. Assembler::assert_signed_range() - // return -(1 << nbits-1) <= x && x < ( 1 << nbits-1), - return (unsigned)(x + (1 << nbits-1)) < (unsigned)(1 << nbits); - } - - // set a signed immediate field - static int set_simm(int insn, int imm, int nbits) { - return (insn &~ Assembler::simm(-1, nbits)) | Assembler::simm(imm, nbits); - } - - // set a wdisp field (disp should be the difference of two addresses) - static int set_wdisp(int insn, intptr_t disp, int nbits) { - return (insn &~ Assembler::wdisp((intptr_t)-4, (intptr_t)0, nbits)) | Assembler::wdisp(disp, 0, nbits); - } - - static int set_wdisp16(int insn, intptr_t disp) { - return (insn &~ Assembler::wdisp16((intptr_t)-4, 0)) | Assembler::wdisp16(disp, 0); - } - - // get a simm13 field from an arithmetic or memory instruction - static int get_simm13(int insn) { - assert(is_either(Assembler::inv_op(insn), - Assembler::arith_op, Assembler::ldst_op) && - (insn & Assembler::immed(true)), "must have a simm13 field"); - return Assembler::inv_simm(insn, 13); - } - - // set the simm13 field of an arithmetic or memory instruction - static bool set_simm13(int insn, int imm) { - get_simm13(insn); // tickle the assertion check - return set_simm(insn, imm, 13); - } - - // combine the fields of a sethi stream (7 instructions ) and an add, jmp or ld/st - static intptr_t data64( address pc, int arith_insn ) { - assert(is_op2(*(unsigned int *)pc, Assembler::sethi_op2), "must be sethi"); - intptr_t hi = (intptr_t)gethi( (unsigned int *)pc ); - intptr_t lo = (intptr_t)get_simm13(arith_insn); - assert((unsigned)lo < (1 << 10), "offset field of set_metadata must be 10 bits"); - return hi | lo; - } - - // Regenerate the instruction sequence that performs the 64 bit - // sethi. This only does the sethi. The disp field (bottom 10 bits) - // must be handled separately. - static void set_data64_sethi(address instaddr, intptr_t x); - static void verify_data64_sethi(address instaddr, intptr_t x); - - // combine the fields of a sethi/simm13 pair (simm13 = or, add, jmpl, ld/st) - static int data32(int sethi_insn, int arith_insn) { - assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi"); - int hi = Assembler::inv_hi22(sethi_insn); - int lo = get_simm13(arith_insn); - assert((unsigned)lo < (1 << 10), "offset field of set_metadata must be 10 bits"); - return hi | lo; - } - - static int set_data32_sethi(int sethi_insn, int imm) { - // note that Assembler::hi22 clips the low 10 bits for us - assert(is_op2(sethi_insn, Assembler::sethi_op2), "must be sethi"); - return (sethi_insn &~ Assembler::hi22(-1)) | Assembler::hi22(imm); - } - - static int set_data32_simm13(int arith_insn, int imm) { - get_simm13(arith_insn); // tickle the assertion check - int imm10 = Assembler::low10(imm); - return (arith_insn &~ Assembler::simm(-1, 13)) | Assembler::simm(imm10, 13); - } - - static int low10(int imm) { - return Assembler::low10(imm); - } - - // Perform the inverse of the LP64 Macroassembler::sethi - // routine. Extracts the 54 bits of address from the instruction - // stream. This routine must agree with the sethi routine in - // assembler_inline_sparc.hpp - static address gethi( unsigned int *pc ) { - int i = 0; - uintptr_t adr; - // We first start out with the real sethi instruction - assert(is_op2(*pc, Assembler::sethi_op2), "in gethi - must be sethi"); - adr = (unsigned int)Assembler::inv_hi22( *(pc++) ); - i++; - while ( i < 7 ) { - // We're done if we hit a nop - if ( (int)*pc == nop_instruction() ) break; - assert ( Assembler::inv_op(*pc) == Assembler::arith_op, "in gethi - must be arith_op" ); - switch ( Assembler::inv_op3(*pc) ) { - case Assembler::xor_op3: - adr ^= (intptr_t)get_simm13( *pc ); - return ( (address)adr ); - break; - case Assembler::sll_op3: - adr <<= ( *pc & 0x3f ); - break; - case Assembler::or_op3: - adr |= (intptr_t)get_simm13( *pc ); - break; - default: - assert ( 0, "in gethi - Should not reach here" ); - break; - } - pc++; - i++; - } - return ( (address)adr ); - } - - public: - void verify(); - void print(); - - // unit test stuff - static void test() {} // override for testing - - inline friend NativeInstruction* nativeInstruction_at(address address); -}; - -inline NativeInstruction* nativeInstruction_at(address address) { - NativeInstruction* inst = (NativeInstruction*)address; -#ifdef ASSERT - inst->verify(); -#endif - return inst; -} - - - -//----------------------------------------------------------------------------- - -// The NativeCall is an abstraction for accessing/manipulating native call imm32 instructions. -// (used to manipulate inline caches, primitive & dll calls, etc.) -class NativeCall; - -inline NativeCall* nativeCall_at(address instr); -inline NativeCall* nativeCall_overwriting_at(address instr, - address destination = NULL); -inline NativeCall* nativeCall_before(address return_address); -class NativeCall: public NativeInstruction { - public: - enum Sparc_specific_constants { - instruction_size = 8, - return_address_offset = 8, - call_displacement_width = 30, - displacement_offset = 0, - instruction_offset = 0 - }; - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(instruction_size); } - address return_address() const { return addr_at(return_address_offset); } - - address destination() const { return inv_wdisp(long_at(0), call_displacement_width) + instruction_address(); } - address displacement_address() const { return addr_at(displacement_offset); } - void set_destination(address dest) { set_long_at(0, set_wdisp(long_at(0), dest - instruction_address(), call_displacement_width)); } - void set_destination_mt_safe(address dest); - - void verify_alignment() {} // do nothing on sparc - void verify(); - void print(); - - // unit test stuff - static void test(); - - // Creation - friend inline NativeCall* nativeCall_at(address instr); - friend NativeCall* nativeCall_overwriting_at(address instr, address destination) { - // insert a "blank" call: - NativeCall* call = (NativeCall*)instr; - call->set_long_at(0 * BytesPerInstWord, call_instruction(destination, instr)); - call->set_long_at(1 * BytesPerInstWord, nop_instruction()); - assert(call->addr_at(2 * BytesPerInstWord) - instr == instruction_size, "instruction size"); - // check its structure now: - assert(nativeCall_at(instr)->destination() == destination, "correct call destination"); - return call; - } - - friend inline NativeCall* nativeCall_before(address return_address) { - NativeCall* call = (NativeCall*)(return_address - return_address_offset); - #ifdef ASSERT - call->verify(); - #endif - return call; - } - - static bool is_call_at(address instr) { - return nativeInstruction_at(instr)->is_call(); - } - - static bool is_call_before(address instr) { - return nativeInstruction_at(instr - return_address_offset)->is_call(); - } - - static bool is_call_to(address instr, address target) { - return nativeInstruction_at(instr)->is_call() && - nativeCall_at(instr)->destination() == target; - } - - // MT-safe patching of a call instruction. - static void insert(address code_pos, address entry) { - (void)nativeCall_overwriting_at(code_pos, entry); - } - - static void replace_mt_safe(address instr_addr, address code_buffer); -}; -inline NativeCall* nativeCall_at(address instr) { - NativeCall* call = (NativeCall*)instr; -#ifdef ASSERT - call->verify(); -#endif - return call; -} - -class NativeCallReg: public NativeInstruction { - public: - enum Sparc_specific_constants { - instruction_size = 8, - return_address_offset = 8, - instruction_offset = 0 - }; - - address next_instruction_address() const { - return addr_at(instruction_size); - } -}; - -// The NativeFarCall is an abstraction for accessing/manipulating native call-anywhere -// instructions in the sparcv9 vm. Used to call native methods which may be loaded -// anywhere in the address space, possibly out of reach of a call instruction. - -// The format of this extended-range call is: -// jumpl_to addr, lreg -// == sethi %hi54(addr), O7 ; jumpl O7, %lo10(addr), O7 ; -// That is, it is essentially the same as a NativeJump. -class NativeFarCall; -inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination = NULL); -inline NativeFarCall* nativeFarCall_at(address instr); -class NativeFarCall: public NativeInstruction { - public: - enum Sparc_specific_constants { - // instruction_size includes the delay slot instruction. - instruction_size = 9 * BytesPerInstWord, - return_address_offset = 9 * BytesPerInstWord, - jmpl_offset = 7 * BytesPerInstWord, - displacement_offset = 0, - instruction_offset = 0 - }; - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(instruction_size); } - address return_address() const { return addr_at(return_address_offset); } - - address destination() const { - return (address) data64(addr_at(0), long_at(jmpl_offset)); - } - address displacement_address() const { return addr_at(displacement_offset); } - void set_destination(address dest); - - bool destination_is_compiled_verified_entry_point(); - - void verify(); - void print(); - - // unit test stuff - static void test(); - - // Creation - friend inline NativeFarCall* nativeFarCall_at(address instr) { - NativeFarCall* call = (NativeFarCall*)instr; - #ifdef ASSERT - call->verify(); - #endif - return call; - } - - friend inline NativeFarCall* nativeFarCall_overwriting_at(address instr, address destination) { - Unimplemented(); - NativeFarCall* call = (NativeFarCall*)instr; - return call; - } - - friend NativeFarCall* nativeFarCall_before(address return_address) { - NativeFarCall* call = (NativeFarCall*)(return_address - return_address_offset); - #ifdef ASSERT - call->verify(); - #endif - return call; - } - - static bool is_call_at(address instr); - - // MT-safe patching of a call instruction. - static void insert(address code_pos, address entry) { - (void)nativeFarCall_overwriting_at(code_pos, entry); - } - static void replace_mt_safe(address instr_addr, address code_buffer); -}; - - -// An interface for accessing/manipulating 32 bit native set_metadata imm, reg instructions -// (used to manipulate inlined data references, etc.) -// set_metadata imm, reg -// == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg -class NativeMovConstReg32; -inline NativeMovConstReg32* nativeMovConstReg32_at(address address); -class NativeMovConstReg32: public NativeInstruction { - public: - enum Sparc_specific_constants { - sethi_offset = 0, - add_offset = 4, - instruction_size = 8 - }; - - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(instruction_size); } - - // (The [set_]data accessor respects oop_type relocs also.) - intptr_t data() const; - void set_data(intptr_t x); - - // report the destination register - Register destination() { return inv_rd(long_at(sethi_offset)); } - - void verify(); - void print(); - - // unit test stuff - static void test(); - - // Creation - friend inline NativeMovConstReg32* nativeMovConstReg32_at(address address) { - NativeMovConstReg32* test = (NativeMovConstReg32*)address; - #ifdef ASSERT - test->verify(); - #endif - return test; - } -}; - -// An interface for accessing/manipulating native set_metadata imm, reg instructions. -// (used to manipulate inlined data references, etc.) -// set_metadata imm, reg -// == sethi %hi22(imm), reg ; add reg, %lo10(imm), reg -class NativeMovConstReg; -inline NativeMovConstReg* nativeMovConstReg_at(address address); -class NativeMovConstReg: public NativeInstruction { - public: - enum Sparc_specific_constants { - sethi_offset = 0, - add_offset = 7 * BytesPerInstWord, - instruction_size = 8 * BytesPerInstWord - }; - - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(instruction_size); } - - // (The [set_]data accessor respects oop_type relocs also.) - intptr_t data() const; - void set_data(intptr_t x); - - // report the destination register - Register destination() { return inv_rd(long_at(sethi_offset)); } - - void verify(); - void print(); - - // unit test stuff - static void test(); - - // Creation - friend inline NativeMovConstReg* nativeMovConstReg_at(address address) { - NativeMovConstReg* test = (NativeMovConstReg*)address; - #ifdef ASSERT - test->verify(); - #endif - return test; - } - - - friend NativeMovConstReg* nativeMovConstReg_before(address address) { - NativeMovConstReg* test = (NativeMovConstReg*)(address - instruction_size); - #ifdef ASSERT - test->verify(); - #endif - return test; - } - -}; - - -// An interface for accessing/manipulating native set_metadata imm, reg instructions. -// (used to manipulate inlined data references, etc.) -// set_metadata imm, reg -// == sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg -// -// Note that it is identical to NativeMovConstReg with the exception of a nop between the -// sethi and the add. The nop is required to be in the delay slot of the call instruction -// which overwrites the sethi during patching. -class NativeMovConstRegPatching; -inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address); -class NativeMovConstRegPatching: public NativeInstruction { - public: - enum Sparc_specific_constants { - sethi_offset = 0, - nop_offset = 7 * BytesPerInstWord, - add_offset = nop_offset + BytesPerInstWord, - instruction_size = add_offset + BytesPerInstWord - }; - - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(instruction_size); } - - // (The [set_]data accessor respects oop_type relocs also.) - int data() const; - void set_data(int x); - - // report the destination register - Register destination() { return inv_rd(long_at(sethi_offset)); } - - void verify(); - void print(); - - // unit test stuff - static void test(); - - // Creation - friend inline NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) { - NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)address; - #ifdef ASSERT - test->verify(); - #endif - return test; - } - - - friend NativeMovConstRegPatching* nativeMovConstRegPatching_before(address address) { - NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_size); - #ifdef ASSERT - test->verify(); - #endif - return test; - } - -}; - - -// An interface for accessing/manipulating native memory ops -// ld* [reg + offset], reg -// st* reg, [reg + offset] -// sethi %hi(imm), reg; add reg, %lo(imm), reg; ld* [reg1 + reg], reg2 -// sethi %hi(imm), reg; add reg, %lo(imm), reg; st* reg2, [reg1 + reg] -// Ops covered: {lds,ldu,st}{w,b,h}, {ld,st}{d,x} -// -class NativeMovRegMem; -inline NativeMovRegMem* nativeMovRegMem_at (address address); -class NativeMovRegMem: public NativeInstruction { - public: - enum Sparc_specific_constants { - op3_mask_ld = 1 << Assembler::lduw_op3 | - 1 << Assembler::ldub_op3 | - 1 << Assembler::lduh_op3 | - 1 << Assembler::ldd_op3 | - 1 << Assembler::ldsw_op3 | - 1 << Assembler::ldsb_op3 | - 1 << Assembler::ldsh_op3 | - 1 << Assembler::ldx_op3, - op3_mask_st = 1 << Assembler::stw_op3 | - 1 << Assembler::stb_op3 | - 1 << Assembler::sth_op3 | - 1 << Assembler::std_op3 | - 1 << Assembler::stx_op3, - op3_ldst_int_limit = Assembler::ldf_op3, - op3_mask_ldf = 1 << (Assembler::ldf_op3 - op3_ldst_int_limit) | - 1 << (Assembler::lddf_op3 - op3_ldst_int_limit), - op3_mask_stf = 1 << (Assembler::stf_op3 - op3_ldst_int_limit) | - 1 << (Assembler::stdf_op3 - op3_ldst_int_limit), - - offset_width = 13, - sethi_offset = 0, - add_offset = 7 * BytesPerInstWord, - ldst_offset = add_offset + BytesPerInstWord - }; - bool is_immediate() const { - // check if instruction is ld* [reg + offset], reg or st* reg, [reg + offset] - int i0 = long_at(0); - return (is_op(i0, Assembler::ldst_op)); - } - - address instruction_address() const { return addr_at(0); } - - int num_bytes_to_end_of_patch() const { - return is_immediate()? BytesPerInstWord : - NativeMovConstReg::instruction_size; - } - - intptr_t offset() const { - return is_immediate()? inv_simm(long_at(0), offset_width) : - nativeMovConstReg_at(addr_at(0))->data(); - } - void set_offset(intptr_t x) { - if (is_immediate()) { - guarantee(fits_in_simm(x, offset_width), "data block offset overflow"); - set_long_at(0, set_simm(long_at(0), x, offset_width)); - } else - nativeMovConstReg_at(addr_at(0))->set_data(x); - } - - void add_offset_in_bytes(intptr_t radd_offset) { - set_offset (offset() + radd_offset); - } - - void verify(); - void print (); - - // unit test stuff - static void test(); - - private: - friend inline NativeMovRegMem* nativeMovRegMem_at (address address) { - NativeMovRegMem* test = (NativeMovRegMem*)address; - #ifdef ASSERT - test->verify(); - #endif - return test; - } -}; - - -// An interface for accessing/manipulating native jumps -// jump_to addr -// == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), G0 ; -// jumpl_to addr, lreg -// == sethi %hi22(addr), temp ; jumpl reg, %lo10(addr), lreg ; -class NativeJump; -inline NativeJump* nativeJump_at(address address); -class NativeJump: public NativeInstruction { - private: - void guarantee_displacement(int disp, int width) { - guarantee(fits_in_simm(disp, width + 2), "branch displacement overflow"); - } - - public: - enum Sparc_specific_constants { - sethi_offset = 0, - jmpl_offset = 7 * BytesPerInstWord, - instruction_size = 9 * BytesPerInstWord // includes delay slot - }; - - address instruction_address() const { return addr_at(0); } - address next_instruction_address() const { return addr_at(instruction_size); } - - address jump_destination() const { - return (address) data64(instruction_address(), long_at(jmpl_offset)); - } - void set_jump_destination(address dest) { - set_data64_sethi( instruction_address(), (intptr_t)dest); - set_long_at(jmpl_offset, set_data32_simm13( long_at(jmpl_offset), (intptr_t)dest)); - } - - // Creation - friend inline NativeJump* nativeJump_at(address address) { - NativeJump* jump = (NativeJump*)address; - #ifdef ASSERT - jump->verify(); - #endif - return jump; - } - - void verify(); - void print(); - - // 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) { - // nothing to do for sparc. - } - static void patch_verified_entry(address entry, address verified_entry, address dest); -}; - - - -// Despite the name, handles only simple branches. -class NativeGeneralJump; -inline NativeGeneralJump* nativeGeneralJump_at(address address); -class NativeGeneralJump: public NativeInstruction { - public: - enum Sparc_specific_constants { - instruction_size = 8 - }; - - address instruction_address() const { return addr_at(0); } - address jump_destination() const { return addr_at(0) + branch_destination_offset(long_at(0)); } - void set_jump_destination(address dest) { - int patched_instr = patch_branch_destination_offset(dest - addr_at(0), long_at(0)); - set_long_at(0, patched_instr); - } - NativeInstruction *delay_slot_instr() { return nativeInstruction_at(addr_at(4));} - void fill_delay_slot(int instr) { set_long_at(4, instr);} - Assembler::Condition condition() { - int x = long_at(0); - return (Assembler::Condition) Assembler::inv_cond(x); - } - - // Creation - friend inline NativeGeneralJump* nativeGeneralJump_at(address address) { - NativeGeneralJump* jump = (NativeGeneralJump*)(address); -#ifdef ASSERT - jump->verify(); -#endif - return jump; - } - - // Insertion of native general jump instruction - static void insert_unconditional(address code_pos, address entry); - static void replace_mt_safe(address instr_addr, address code_buffer); - - void verify(); -}; - - -class NativeIllegalInstruction: public NativeInstruction { - public: - enum Sparc_specific_constants { - instruction_size = 4 - }; - - // Insert illegal opcode as specific address - static void insert(address code_pos); -}; - -#endif // CPU_SPARC_NATIVEINST_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/registerMap_sparc.hpp b/src/hotspot/cpu/sparc/registerMap_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/registerMap_sparc.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef CPU_SPARC_REGISTERMAP_SPARC_HPP -#define CPU_SPARC_REGISTERMAP_SPARC_HPP - -// machine-dependent implemention for register maps - friend class frame; - friend class MethodHandles; - - private: - intptr_t* _window; // register window save area (for L and I regs) - intptr_t* _younger_window; // previous save area (for O regs, if needed) - - address pd_location(VMReg reg) const; - void pd_clear(); - void pd_initialize_from(const RegisterMap* map) { - _window = map->_window; - _younger_window = map->_younger_window; - _location_valid[0] = 0; // avoid the shift_individual_registers game - } - void pd_initialize() { - _window = NULL; - _younger_window = NULL; - _location_valid[0] = 0; // avoid the shift_individual_registers game - } - void shift_window(intptr_t* sp, intptr_t* younger_sp) { - _window = sp; - _younger_window = younger_sp; - // Throw away locations for %i, %o, and %l registers: - // But do not throw away %g register locs. - if (_location_valid[0] != 0) shift_individual_registers(); - } - void shift_individual_registers(); - // When popping out of compiled frames, we make all IRegs disappear. - void make_integer_regs_unsaved() { _location_valid[0] = 0; } - -#endif // CPU_SPARC_REGISTERMAP_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/register_definitions_sparc.cpp b/src/hotspot/cpu/sparc/register_definitions_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/register_definitions_sparc.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2002, 2016, 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. - * - */ - -// Note: precompiled headers can not be used in this file because of the above -// definition - -#include "asm/assembler.hpp" -#include "asm/register.hpp" -#include "interp_masm_sparc.hpp" -#include "register_sparc.hpp" - -REGISTER_DEFINITION(Register, noreg); - -REGISTER_DEFINITION(Register, G0); -REGISTER_DEFINITION(Register, G1); -REGISTER_DEFINITION(Register, G2); -REGISTER_DEFINITION(Register, G3); -REGISTER_DEFINITION(Register, G4); -REGISTER_DEFINITION(Register, G5); -REGISTER_DEFINITION(Register, G6); -REGISTER_DEFINITION(Register, G7); - -REGISTER_DEFINITION(Register, O0); -REGISTER_DEFINITION(Register, O1); -REGISTER_DEFINITION(Register, O2); -REGISTER_DEFINITION(Register, O3); -REGISTER_DEFINITION(Register, O4); -REGISTER_DEFINITION(Register, O5); -REGISTER_DEFINITION(Register, O6); -REGISTER_DEFINITION(Register, O7); - -REGISTER_DEFINITION(Register, L0); -REGISTER_DEFINITION(Register, L1); -REGISTER_DEFINITION(Register, L2); -REGISTER_DEFINITION(Register, L3); -REGISTER_DEFINITION(Register, L4); -REGISTER_DEFINITION(Register, L5); -REGISTER_DEFINITION(Register, L6); -REGISTER_DEFINITION(Register, L7); - -REGISTER_DEFINITION(Register, I0); -REGISTER_DEFINITION(Register, I1); -REGISTER_DEFINITION(Register, I2); -REGISTER_DEFINITION(Register, I3); -REGISTER_DEFINITION(Register, I4); -REGISTER_DEFINITION(Register, I5); -REGISTER_DEFINITION(Register, I6); -REGISTER_DEFINITION(Register, I7); - -REGISTER_DEFINITION(Register, FP); -REGISTER_DEFINITION(Register, SP); - -REGISTER_DEFINITION(FloatRegister, fnoreg); -REGISTER_DEFINITION(FloatRegister, F0); -REGISTER_DEFINITION(FloatRegister, F1); -REGISTER_DEFINITION(FloatRegister, F2); -REGISTER_DEFINITION(FloatRegister, F3); -REGISTER_DEFINITION(FloatRegister, F4); -REGISTER_DEFINITION(FloatRegister, F5); -REGISTER_DEFINITION(FloatRegister, F6); -REGISTER_DEFINITION(FloatRegister, F7); -REGISTER_DEFINITION(FloatRegister, F8); -REGISTER_DEFINITION(FloatRegister, F9); -REGISTER_DEFINITION(FloatRegister, F10); -REGISTER_DEFINITION(FloatRegister, F11); -REGISTER_DEFINITION(FloatRegister, F12); -REGISTER_DEFINITION(FloatRegister, F13); -REGISTER_DEFINITION(FloatRegister, F14); -REGISTER_DEFINITION(FloatRegister, F15); -REGISTER_DEFINITION(FloatRegister, F16); -REGISTER_DEFINITION(FloatRegister, F17); -REGISTER_DEFINITION(FloatRegister, F18); -REGISTER_DEFINITION(FloatRegister, F19); -REGISTER_DEFINITION(FloatRegister, F20); -REGISTER_DEFINITION(FloatRegister, F21); -REGISTER_DEFINITION(FloatRegister, F22); -REGISTER_DEFINITION(FloatRegister, F23); -REGISTER_DEFINITION(FloatRegister, F24); -REGISTER_DEFINITION(FloatRegister, F25); -REGISTER_DEFINITION(FloatRegister, F26); -REGISTER_DEFINITION(FloatRegister, F27); -REGISTER_DEFINITION(FloatRegister, F28); -REGISTER_DEFINITION(FloatRegister, F29); -REGISTER_DEFINITION(FloatRegister, F30); -REGISTER_DEFINITION(FloatRegister, F31); -REGISTER_DEFINITION(FloatRegister, F32); -REGISTER_DEFINITION(FloatRegister, F34); -REGISTER_DEFINITION(FloatRegister, F36); -REGISTER_DEFINITION(FloatRegister, F38); -REGISTER_DEFINITION(FloatRegister, F40); -REGISTER_DEFINITION(FloatRegister, F42); -REGISTER_DEFINITION(FloatRegister, F44); -REGISTER_DEFINITION(FloatRegister, F46); -REGISTER_DEFINITION(FloatRegister, F48); -REGISTER_DEFINITION(FloatRegister, F50); -REGISTER_DEFINITION(FloatRegister, F52); -REGISTER_DEFINITION(FloatRegister, F54); -REGISTER_DEFINITION(FloatRegister, F56); -REGISTER_DEFINITION(FloatRegister, F58); -REGISTER_DEFINITION(FloatRegister, F60); -REGISTER_DEFINITION(FloatRegister, F62); - - -REGISTER_DEFINITION( Register, Otos_i); -REGISTER_DEFINITION( Register, Otos_l); -REGISTER_DEFINITION( Register, Otos_l1); -REGISTER_DEFINITION( Register, Otos_l2); -REGISTER_DEFINITION(FloatRegister, Ftos_f); -REGISTER_DEFINITION(FloatRegister, Ftos_d); -REGISTER_DEFINITION(FloatRegister, Ftos_d1); -REGISTER_DEFINITION(FloatRegister, Ftos_d2); - - -REGISTER_DEFINITION(Register, G2_thread); -REGISTER_DEFINITION(Register, G6_heapbase); -REGISTER_DEFINITION(Register, G5_method); -REGISTER_DEFINITION(Register, G5_megamorphic_method); -REGISTER_DEFINITION(Register, G5_inline_cache_reg); -REGISTER_DEFINITION(Register, Gargs); -REGISTER_DEFINITION(Register, L7_thread_cache); -REGISTER_DEFINITION(Register, Gframe_size); -REGISTER_DEFINITION(Register, G1_scratch); -REGISTER_DEFINITION(Register, G3_scratch); -REGISTER_DEFINITION(Register, G4_scratch); -REGISTER_DEFINITION(Register, Gtemp); -REGISTER_DEFINITION(Register, Lentry_args); - -// JSR 292 -REGISTER_DEFINITION(Register, G5_method_type); -REGISTER_DEFINITION(Register, G3_method_handle); -REGISTER_DEFINITION(Register, L7_mh_SP_save); - -REGISTER_DEFINITION(Register, Lesp); -REGISTER_DEFINITION(Register, Lbcp); -REGISTER_DEFINITION(Register, Lmonitors); -REGISTER_DEFINITION(Register, Lbyte_code); -REGISTER_DEFINITION(Register, Llast_SP); -REGISTER_DEFINITION(Register, Lscratch); -REGISTER_DEFINITION(Register, Lscratch2); -REGISTER_DEFINITION(Register, LcpoolCache); -REGISTER_DEFINITION(Register, I5_savedSP); -REGISTER_DEFINITION(Register, O5_savedSP); -REGISTER_DEFINITION(Register, IdispatchAddress); -REGISTER_DEFINITION(Register, ImethodDataPtr); -REGISTER_DEFINITION(Register, Lmethod); -REGISTER_DEFINITION(Register, Llocals); -REGISTER_DEFINITION(Register, Oexception); -REGISTER_DEFINITION(Register, Oissuing_pc); diff --git a/src/hotspot/cpu/sparc/register_sparc.cpp b/src/hotspot/cpu/sparc/register_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/register_sparc.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2000, 2010, 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. - * - */ - -#include "precompiled.hpp" -#include "register_sparc.hpp" - -const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers << 1; -const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr + FloatRegisterImpl::number_of_registers; - -const char* RegisterImpl::name() const { - const char* names[number_of_registers] = { - "G0", "G1", "G2", "G3", "G4", "G5", "G6", "G7", - "O0", "O1", "O2", "O3", "O4", "O5", "SP", "O7", - "L0", "L1", "L2", "L3", "L4", "L5", "L6", "L7", - "I0", "I1", "I2", "I3", "I4", "I5", "FP", "I7" - }; - return is_valid() ? names[encoding()] : "noreg"; -} - - -const char* FloatRegisterImpl::name() const { - const char* names[number_of_registers] = { - "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", - "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "F19", - "F20", "F21", "F22", "F23", "F24", "F25", "F26", "F27", "F28", "F29", - "F30", "F31", "F32", "F33?", "F34", "F35?", "F36", "F37?", "F38", "F39?", - "F40", "F41?", "F42", "F43?", "F44", "F45?", "F46", "F47?", "F48", "F49?", - "F50", "F51?", "F52", "F53?", "F54", "F55?", "F56", "F57?", "F58", "F59?", - "F60", "F61?", "F62" - }; - return is_valid() ? names[encoding()] : "fnoreg"; -} diff --git a/src/hotspot/cpu/sparc/register_sparc.hpp b/src/hotspot/cpu/sparc/register_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/register_sparc.hpp +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef CPU_SPARC_REGISTER_SPARC_HPP -#define CPU_SPARC_REGISTER_SPARC_HPP - -#include "asm/register.hpp" - -// forward declaration -class Address; -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; -} - -// The implementation of integer registers for the SPARC architecture -class RegisterImpl: public AbstractRegisterImpl { - public: - enum { - log_set_size = 3, // the number of bits to encode the set register number - number_of_sets = 4, // the number of registers sets (in, local, out, global) - number_of_registers = number_of_sets << log_set_size, - - iset_no = 3, ibase = iset_no << log_set_size, // the in register set - lset_no = 2, lbase = lset_no << log_set_size, // the local register set - oset_no = 1, obase = oset_no << log_set_size, // the output register set - gset_no = 0, gbase = gset_no << log_set_size // the global register set - }; - - - friend Register as_Register(int encoding); - // set specific construction - friend Register as_iRegister(int number); - friend Register as_lRegister(int number); - friend Register as_oRegister(int number); - friend Register as_gRegister(int number); - - inline VMReg as_VMReg(); - - // accessors - int encoding() const { assert(is_valid(), "invalid register"); return value(); } - const char* name() const; - - // testers - bool is_valid() const { return (0 <= (value()&0x7F) && (value()&0x7F) < number_of_registers); } - bool is_even() const { return (encoding() & 1) == 0; } - bool is_in() const { return (encoding() >> log_set_size) == iset_no; } - bool is_local() const { return (encoding() >> log_set_size) == lset_no; } - bool is_out() const { return (encoding() >> log_set_size) == oset_no; } - bool is_global() const { return (encoding() >> log_set_size) == gset_no; } - - // derived registers, offsets, and addresses - Register successor() const { return as_Register(encoding() + 1); } - - int input_number() const { - assert(is_in(), "must be input register"); - return encoding() - ibase; - } - - Register after_save() const { - assert(is_out() || is_global(), "register not visible after save"); - return is_out() ? as_Register(encoding() + (ibase - obase)) : (const Register)this; - } - - Register after_restore() const { - assert(is_in() || is_global(), "register not visible after restore"); - return is_in() ? as_Register(encoding() + (obase - ibase)) : (const Register)this; - } - - int sp_offset_in_saved_window() const { - assert(is_in() || is_local(), "only i and l registers are saved in frame"); - return encoding() - lbase; - } - - inline Address address_in_saved_window() const; // implemented in assembler_sparc.hpp -}; - - -// set specific construction -inline Register as_iRegister(int number) { return as_Register(RegisterImpl::ibase + number); } -inline Register as_lRegister(int number) { return as_Register(RegisterImpl::lbase + number); } -inline Register as_oRegister(int number) { return as_Register(RegisterImpl::obase + number); } -inline Register as_gRegister(int number) { return as_Register(RegisterImpl::gbase + number); } - -// The integer registers of the SPARC architecture - -CONSTANT_REGISTER_DECLARATION(Register, noreg , (-1)); - -CONSTANT_REGISTER_DECLARATION(Register, G0 , (RegisterImpl::gbase + 0)); -CONSTANT_REGISTER_DECLARATION(Register, G1 , (RegisterImpl::gbase + 1)); -CONSTANT_REGISTER_DECLARATION(Register, G2 , (RegisterImpl::gbase + 2)); -CONSTANT_REGISTER_DECLARATION(Register, G3 , (RegisterImpl::gbase + 3)); -CONSTANT_REGISTER_DECLARATION(Register, G4 , (RegisterImpl::gbase + 4)); -CONSTANT_REGISTER_DECLARATION(Register, G5 , (RegisterImpl::gbase + 5)); -CONSTANT_REGISTER_DECLARATION(Register, G6 , (RegisterImpl::gbase + 6)); -CONSTANT_REGISTER_DECLARATION(Register, G7 , (RegisterImpl::gbase + 7)); - -CONSTANT_REGISTER_DECLARATION(Register, O0 , (RegisterImpl::obase + 0)); -CONSTANT_REGISTER_DECLARATION(Register, O1 , (RegisterImpl::obase + 1)); -CONSTANT_REGISTER_DECLARATION(Register, O2 , (RegisterImpl::obase + 2)); -CONSTANT_REGISTER_DECLARATION(Register, O3 , (RegisterImpl::obase + 3)); -CONSTANT_REGISTER_DECLARATION(Register, O4 , (RegisterImpl::obase + 4)); -CONSTANT_REGISTER_DECLARATION(Register, O5 , (RegisterImpl::obase + 5)); -CONSTANT_REGISTER_DECLARATION(Register, O6 , (RegisterImpl::obase + 6)); -CONSTANT_REGISTER_DECLARATION(Register, O7 , (RegisterImpl::obase + 7)); - -CONSTANT_REGISTER_DECLARATION(Register, L0 , (RegisterImpl::lbase + 0)); -CONSTANT_REGISTER_DECLARATION(Register, L1 , (RegisterImpl::lbase + 1)); -CONSTANT_REGISTER_DECLARATION(Register, L2 , (RegisterImpl::lbase + 2)); -CONSTANT_REGISTER_DECLARATION(Register, L3 , (RegisterImpl::lbase + 3)); -CONSTANT_REGISTER_DECLARATION(Register, L4 , (RegisterImpl::lbase + 4)); -CONSTANT_REGISTER_DECLARATION(Register, L5 , (RegisterImpl::lbase + 5)); -CONSTANT_REGISTER_DECLARATION(Register, L6 , (RegisterImpl::lbase + 6)); -CONSTANT_REGISTER_DECLARATION(Register, L7 , (RegisterImpl::lbase + 7)); - -CONSTANT_REGISTER_DECLARATION(Register, I0 , (RegisterImpl::ibase + 0)); -CONSTANT_REGISTER_DECLARATION(Register, I1 , (RegisterImpl::ibase + 1)); -CONSTANT_REGISTER_DECLARATION(Register, I2 , (RegisterImpl::ibase + 2)); -CONSTANT_REGISTER_DECLARATION(Register, I3 , (RegisterImpl::ibase + 3)); -CONSTANT_REGISTER_DECLARATION(Register, I4 , (RegisterImpl::ibase + 4)); -CONSTANT_REGISTER_DECLARATION(Register, I5 , (RegisterImpl::ibase + 5)); -CONSTANT_REGISTER_DECLARATION(Register, I6 , (RegisterImpl::ibase + 6)); -CONSTANT_REGISTER_DECLARATION(Register, I7 , (RegisterImpl::ibase + 7)); - -CONSTANT_REGISTER_DECLARATION(Register, FP , (RegisterImpl::ibase + 6)); -CONSTANT_REGISTER_DECLARATION(Register, SP , (RegisterImpl::obase + 6)); - -// Use FloatRegister as shortcut -class FloatRegisterImpl; -typedef FloatRegisterImpl* FloatRegister; - - -// construction -inline FloatRegister as_FloatRegister(int encoding) { - return (FloatRegister)(intptr_t)encoding; -} - -// The implementation of float registers for the SPARC architecture - -class FloatRegisterImpl: public AbstractRegisterImpl { - public: - enum { - number_of_registers = 64 - }; - - enum Width { - S = 1, D = 2, Q = 3 - }; - - // construction - inline VMReg as_VMReg( ); - - // accessors - int encoding() const { assert(is_valid(), "invalid register"); return value(); } - - public: - int encoding(Width w) const { - const int c = encoding(); - switch (w) { - case S: - assert(c < 32, "bad single float register"); - return c; - - case D: - assert(c < 64 && (c & 1) == 0, "bad double float register"); - return (c & 0x1e) | ((c & 0x20) >> 5); - - case Q: - assert(c < 64 && (c & 3) == 0, "bad quad float register"); - return (c & 0x1c) | ((c & 0x20) >> 5); - } - ShouldNotReachHere(); - return -1; - } - - bool is_valid() const { return 0 <= value() && value() < number_of_registers; } - bool is_even() const { return (encoding() & 1) == 0; } - - const char* name() const; - - FloatRegister successor() const { return as_FloatRegister(encoding() + 1); } -}; - - -// The float registers of the SPARC architecture - -CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg , (-1)); - -CONSTANT_REGISTER_DECLARATION(FloatRegister, F0 , ( 0)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F1 , ( 1)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F2 , ( 2)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F3 , ( 3)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F4 , ( 4)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F5 , ( 5)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F6 , ( 6)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F7 , ( 7)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F8 , ( 8)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F9 , ( 9)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F10 , (10)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F11 , (11)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F12 , (12)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F13 , (13)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F14 , (14)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F15 , (15)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F16 , (16)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F17 , (17)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F18 , (18)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F19 , (19)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F20 , (20)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F21 , (21)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F22 , (22)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F23 , (23)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F24 , (24)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F25 , (25)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F26 , (26)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F27 , (27)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F28 , (28)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F29 , (29)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F30 , (30)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F31 , (31)); - -CONSTANT_REGISTER_DECLARATION(FloatRegister, F32 , (32)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F34 , (34)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F36 , (36)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F38 , (38)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F40 , (40)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F42 , (42)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F44 , (44)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F46 , (46)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F48 , (48)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F50 , (50)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F52 , (52)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F54 , (54)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F56 , (56)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F58 , (58)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F60 , (60)); -CONSTANT_REGISTER_DECLARATION(FloatRegister, F62 , (62)); - -// Maximum number of incoming arguments that can be passed in i registers. -const int SPARC_ARGS_IN_REGS_NUM = 6; - -class ConcreteRegisterImpl : public AbstractRegisterImpl { - public: - enum { - // 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 + - FloatRegisterImpl::number_of_registers + - 1 + // ccr - 4 // fcc - }; - static const int max_gpr; - static const int max_fpr; - -}; - -// Single, Double and Quad fp reg classes. These exist to map the ADLC -// encoding for a floating point register, to the FloatRegister number -// desired by the macroassembler. A FloatRegister is a number between -// 0 and 63 passed around as a pointer. For ADLC, an fp register encoding -// is the actual bit encoding used by the sparc hardware. When ADLC used -// the macroassembler to generate an instruction that references, e.g., a -// double fp reg, it passed the bit encoding to the macroassembler via -// as_FloatRegister, which, for double regs > 30, returns an illegal -// register number. -// -// Therefore we provide the following classes for use by ADLC. Their -// sole purpose is to convert from sparc register encodings to FloatRegisters. -// At some future time, we might replace FloatRegister with these classes, -// hence the definitions of as_xxxFloatRegister as class methods rather -// than as external inline routines. - -class SingleFloatRegisterImpl; -typedef SingleFloatRegisterImpl *SingleFloatRegister; - -inline FloatRegister as_SingleFloatRegister(int encoding); -class SingleFloatRegisterImpl { - public: - friend inline FloatRegister as_SingleFloatRegister(int encoding) { - assert(encoding < 32, "bad single float register encoding"); - return as_FloatRegister(encoding); - } -}; - - -class DoubleFloatRegisterImpl; -typedef DoubleFloatRegisterImpl *DoubleFloatRegister; - -inline FloatRegister as_DoubleFloatRegister(int encoding); -class DoubleFloatRegisterImpl { - public: - friend inline FloatRegister as_DoubleFloatRegister(int encoding) { - assert(encoding < 32, "bad double float register encoding"); - return as_FloatRegister( ((encoding & 1) << 5) | (encoding & 0x1e) ); - } -}; - - -class QuadFloatRegisterImpl; -typedef QuadFloatRegisterImpl *QuadFloatRegister; - -class QuadFloatRegisterImpl { - public: - friend FloatRegister as_QuadFloatRegister(int encoding) { - assert(encoding < 32 && ((encoding & 2) == 0), "bad quad float register encoding"); - return as_FloatRegister( ((encoding & 1) << 5) | (encoding & 0x1c) ); - } -}; - -#endif // CPU_SPARC_REGISTER_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/relocInfo_sparc.cpp b/src/hotspot/cpu/sparc/relocInfo_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/relocInfo_sparc.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 1998, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/relocInfo.hpp" -#include "nativeInst_sparc.hpp" -#include "oops/compressedOops.inline.hpp" -#include "oops/klass.inline.hpp" -#include "oops/oop.hpp" -#include "runtime/safepoint.hpp" - -void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { - NativeInstruction* ip = nativeInstruction_at(addr()); - jint inst = ip->long_at(0); - assert(inst != NativeInstruction::illegal_instruction(), "no breakpoint"); - switch (Assembler::inv_op(inst)) { - - case Assembler::ldst_op: - #ifdef ASSERT - switch (Assembler::inv_op3(inst)) { - case Assembler::lduw_op3: - case Assembler::ldub_op3: - case Assembler::lduh_op3: - case Assembler::ldd_op3: - case Assembler::ldsw_op3: - case Assembler::ldsb_op3: - case Assembler::ldsh_op3: - case Assembler::ldx_op3: - case Assembler::ldf_op3: - case Assembler::lddf_op3: - case Assembler::stw_op3: - case Assembler::stb_op3: - case Assembler::sth_op3: - case Assembler::std_op3: - case Assembler::stx_op3: - case Assembler::stf_op3: - case Assembler::stdf_op3: - case Assembler::casa_op3: - case Assembler::casxa_op3: - break; - default: - ShouldNotReachHere(); - } - goto do_non_sethi; - #endif - - case Assembler::arith_op: - #ifdef ASSERT - switch (Assembler::inv_op3(inst)) { - case Assembler::or_op3: - case Assembler::add_op3: - case Assembler::jmpl_op3: - break; - default: - ShouldNotReachHere(); - } - do_non_sethi:; - #endif - { - guarantee(Assembler::inv_immed(inst), "must have a simm13 field"); - int simm13 = Assembler::low10((intptr_t)x) + o; - guarantee(Assembler::is_simm13(simm13), "offset can't overflow simm13"); - inst &= ~Assembler::simm( -1, 13); - inst |= Assembler::simm(simm13, 13); - if (verify_only) { - guarantee(ip->long_at(0) == inst, "instructions must match"); - } else { - ip->set_long_at(0, inst); - } - } - break; - - case Assembler::branch_op: - { - jint inst2; - guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi"); - if (format() != 0) { - assert(type() == relocInfo::oop_type || type() == relocInfo::metadata_type, "only narrow oops or klasses case"); - jint np = type() == relocInfo::oop_type ? CompressedOops::encode((oop)x) : CompressedKlassPointers::encode((Klass*)x); - inst &= ~Assembler::hi22(-1); - inst |= Assembler::hi22((intptr_t)np); - if (verify_only) { - guarantee(ip->long_at(0) == inst, "instructions must match"); - } else { - ip->set_long_at(0, inst); - } - inst2 = ip->long_at( NativeInstruction::nop_instruction_size ); - guarantee(Assembler::inv_op(inst2)==Assembler::arith_op, "arith op"); - if (verify_only) { - guarantee(ip->long_at(NativeInstruction::nop_instruction_size) == NativeInstruction::set_data32_simm13( inst2, (intptr_t)np), - "instructions must match"); - } else { - ip->set_long_at(NativeInstruction::nop_instruction_size, NativeInstruction::set_data32_simm13( inst2, (intptr_t)np)); - } - break; - } - if (verify_only) { - ip->verify_data64_sethi( ip->addr_at(0), (intptr_t)x ); - } else { - ip->set_data64_sethi( ip->addr_at(0), (intptr_t)x ); - } - } - break; - - default: - guarantee(false, "instruction must perform arithmetic or memory access"); - } -} - - -address Relocation::pd_call_destination(address orig_addr) { - intptr_t adj = 0; - if (orig_addr != NULL) { - // We just moved this call instruction from orig_addr to addr(). - // This means its target will appear to have grown by addr() - orig_addr. - adj = -( addr() - orig_addr ); - } - if (NativeCall::is_call_at(addr())) { - NativeCall* call = nativeCall_at(addr()); - return call->destination() + adj; - } - if (NativeFarCall::is_call_at(addr())) { - NativeFarCall* call = nativeFarCall_at(addr()); - return call->destination() + adj; - } - // Special case: Patchable branch local to the code cache. - // This will break badly if the code cache grows larger than a few Mb. - NativeGeneralJump* br = nativeGeneralJump_at(addr()); - return br->jump_destination() + adj; -} - - -void Relocation::pd_set_call_destination(address x) { - if (NativeCall::is_call_at(addr())) { - NativeCall* call = nativeCall_at(addr()); - call->set_destination(x); - return; - } - if (NativeFarCall::is_call_at(addr())) { - NativeFarCall* call = nativeFarCall_at(addr()); - call->set_destination(x); - return; - } - // Special case: Patchable branch local to the code cache. - // This will break badly if the code cache grows larger than a few Mb. - NativeGeneralJump* br = nativeGeneralJump_at(addr()); - br->set_jump_destination(x); -} - - -address* Relocation::pd_address_in_code() { - // SPARC never embeds addresses in code, at present. - //assert(type() == relocInfo::oop_type, "only oops are inlined at present"); - return (address*)addr(); -} - - -address Relocation::pd_get_address_from_code() { - // SPARC never embeds addresses in code, at present. - //assert(type() == relocInfo::oop_type, "only oops are inlined at present"); - return *(address*)addr(); -} - -void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { -} - -void metadata_Relocation::pd_fix_value(address x) { -} diff --git a/src/hotspot/cpu/sparc/relocInfo_sparc.hpp b/src/hotspot/cpu/sparc/relocInfo_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/relocInfo_sparc.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_RELOCINFO_SPARC_HPP -#define CPU_SPARC_RELOCINFO_SPARC_HPP - - // machine-dependent parts of class relocInfo - private: - enum { - // Since SPARC instructions are whole words, - // the two low-order offset bits can always be discarded. - offset_unit = 4, - - // There is no need for format bits; the instructions are - // sufficiently self-identifying. - // Except narrow oops in 64-bits VM. - format_width = 1 - }; - - public: - - // This platform has no oops in the code that are not also - // listed in the oop section. - static bool mustIterateImmediateOopsInCode() { return false; } - -//Reconciliation History -// 1.3 97/10/15 15:38:36 relocInfo_i486.hpp -// 1.4 97/12/08 16:01:06 relocInfo_i486.hpp -// 1.5 98/01/23 01:34:55 relocInfo_i486.hpp -// 1.6 98/02/27 15:44:53 relocInfo_i486.hpp -// 1.6 98/03/12 14:47:13 relocInfo_i486.hpp -// 1.8 99/06/22 16:37:50 relocInfo_i486.hpp -// 1.9 99/07/16 11:12:11 relocInfo_i486.hpp -//End - -#endif // CPU_SPARC_RELOCINFO_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/runtime_sparc.cpp b/src/hotspot/cpu/sparc/runtime_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/runtime_sparc.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 1998, 2016, 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. - * - */ - -#include "precompiled.hpp" -#ifdef COMPILER2 -#include "asm/macroAssembler.inline.hpp" -#include "classfile/systemDictionary.hpp" -#include "code/vmreg.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_sparc.hpp" -#include "opto/runtime.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/globalDefinitions.hpp" -#include "vmreg_sparc.inline.hpp" -#endif - - -#define __ masm-> - -//------------------------------ generate_exception_blob --------------------------- -// creates exception blob at the end -// Using exception blob, this code is jumped from a compiled method. -// (see emit_exception_handler in sparc.ad file) -// -// Given an exception pc at a call we call into the runtime for the -// handler in this method. This handler might merely restore state -// (i.e. callee save registers) unwind the frame and jump to the -// exception handler for the nmethod if there is no Java level handler -// for the nmethod. -// -// This code is entered with a jmp. -// -// Arguments: -// O0: exception oop -// O1: exception pc -// -// Results: -// O0: exception oop -// O1: exception pc in caller or ??? -// destination: exception handler of caller -// -// Note: the exception pc MUST be at a call (precise debug information) -// -void OptoRuntime::generate_exception_blob() { - // allocate space for code - ResourceMark rm; - int pad = VerifyThread ? 256 : 0;// Extra slop space for more verify code - - // setup code generation tools - // Measured 8/7/03 at 256 in 32bit debug build (no VerifyThread) - // Measured 8/7/03 at 528 in 32bit debug build (VerifyThread) - CodeBuffer buffer("exception_blob", 600+pad, 512); - MacroAssembler* masm = new MacroAssembler(&buffer); - - int framesize_in_bytes = __ total_frame_size_in_bytes(0); - int framesize_in_words = framesize_in_bytes / wordSize; - int framesize_in_slots = framesize_in_bytes / sizeof(jint); - - Label L; - - int start = __ offset(); - - __ verify_thread(); - __ st_ptr(Oexception, G2_thread, JavaThread::exception_oop_offset()); - __ st_ptr(Oissuing_pc, G2_thread, JavaThread::exception_pc_offset()); - - // This call does all the hard work. It checks if an exception catch - // exists in the method. - // If so, it returns the handler address. - // If the nmethod has been deoptimized and it had a handler the handler - // address is the deopt blob unpack_with_exception entry. - // - // If no handler exists it prepares for stack-unwinding, restoring the callee-save - // registers of the frame being removed. - // - __ save_frame(0); - - __ mov(G2_thread, O0); - __ set_last_Java_frame(SP, noreg); - __ save_thread(L7_thread_cache); - - // This call can block at exit and nmethod can be deoptimized at that - // point. If the nmethod had a catch point we would jump to the - // now deoptimized catch point and fall thru the vanilla deopt - // path and lose the exception - // Sure would be simpler if this call didn't block! - __ call(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C), relocInfo::runtime_call_type); - __ delayed()->mov(L7_thread_cache, O0); - - // Set an oopmap for the call site. This oopmap will only be used if we - // are unwinding the stack. Hence, all locations will be dead. - // Callee-saved registers will be the same as the frame above (i.e., - // handle_exception_stub), since they were restored when we got the - // exception. - - OopMapSet *oop_maps = new OopMapSet(); - oop_maps->add_gc_map( __ offset()-start, new OopMap(framesize_in_slots, 0)); - - __ bind(L); - __ restore_thread(L7_thread_cache); - __ reset_last_Java_frame(); - - __ mov(O0, G3_scratch); // Move handler address to temp - __ restore(); - - // Restore SP from L7 if the exception PC is a MethodHandle call site. - __ lduw(Address(G2_thread, JavaThread::is_method_handle_return_offset()), O7); - __ tst(O7); - __ movcc(Assembler::notZero, false, Assembler::icc, L7_mh_SP_save, SP); - - // G3_scratch contains handler address - // Since this may be the deopt blob we must set O7 to look like we returned - // from the original pc that threw the exception - - __ ld_ptr(G2_thread, JavaThread::exception_pc_offset(), O7); - __ sub(O7, frame::pc_return_offset, O7); - - - assert(Assembler::is_simm13(in_bytes(JavaThread::exception_oop_offset())), "exception offset overflows simm13, following ld instruction cannot be in delay slot"); - __ ld_ptr(G2_thread, JavaThread::exception_oop_offset(), Oexception); // O0 -#ifdef ASSERT - __ st_ptr(G0, G2_thread, JavaThread::exception_handler_pc_offset()); - __ st_ptr(G0, G2_thread, JavaThread::exception_pc_offset()); -#endif - __ JMP(G3_scratch, 0); - // Clear the exception oop so GC no longer processes it as a root. - __ delayed()->st_ptr(G0, G2_thread, JavaThread::exception_oop_offset()); - - // ------------- - // make sure all code is generated - masm->flush(); - - _exception_blob = ExceptionBlob::create(&buffer, oop_maps, framesize_in_words); -} diff --git a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp +++ /dev/null @@ -1,3248 +0,0 @@ -/* - * Copyright (c) 2003, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/debugInfoRec.hpp" -#include "code/icBuffer.hpp" -#include "code/vtableStubs.hpp" -#include "gc/shared/gcLocker.hpp" -#include "interpreter/interpreter.hpp" -#include "logging/log.hpp" -#include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" -#include "oops/klass.inline.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/vframeArray.hpp" -#include "utilities/align.hpp" -#include "vmreg_sparc.inline.hpp" -#ifdef COMPILER1 -#include "c1/c1_Runtime1.hpp" -#endif -#ifdef COMPILER2 -#include "opto/runtime.hpp" -#endif -#if INCLUDE_JVMCI -#include "jvmci/jvmciJavaClasses.hpp" -#endif - -#define __ masm-> - - -class RegisterSaver { - - // Used for saving volatile registers. This is Gregs, Fregs, I/L/O. - // The Oregs are problematic. In the 32bit build the compiler can - // have O registers live with 64 bit quantities. A window save will - // cut the heads off of the registers. We have to do a very extensive - // stack dance to save and restore these properly. - - // Note that the Oregs problem only exists if we block at either a polling - // page exception a compiled code safepoint that was not originally a call - // or deoptimize following one of these kinds of safepoints. - - // Lots of registers to save. For all builds, a window save will preserve - // the %i and %l registers. For the 32-bit longs-in-two entries and 64-bit - // builds a window-save will preserve the %o registers. In the LION build - // we need to save the 64-bit %o registers which requires we save them - // before the window-save (as then they become %i registers and get their - // heads chopped off on interrupt). We have to save some %g registers here - // as well. - enum { - // This frame's save area. Includes extra space for the native call: - // vararg's layout space and the like. Briefly holds the caller's - // register save area. - call_args_area = frame::register_save_words_sp_offset + - frame::memory_parameter_word_sp_offset*wordSize, - // Make sure save locations are always 8 byte aligned. - // can't use align_up because it doesn't produce compile time constant - start_of_extra_save_area = ((call_args_area + 7) & ~7), - g1_offset = start_of_extra_save_area, // g-regs needing saving - g3_offset = g1_offset+8, - g4_offset = g3_offset+8, - g5_offset = g4_offset+8, - o0_offset = g5_offset+8, - o1_offset = o0_offset+8, - o2_offset = o1_offset+8, - o3_offset = o2_offset+8, - o4_offset = o3_offset+8, - o5_offset = o4_offset+8, - start_of_flags_save_area = o5_offset+8, - ccr_offset = start_of_flags_save_area, - fsr_offset = ccr_offset + 8, - d00_offset = fsr_offset+8, // Start of float save area - register_save_size = d00_offset+8*32 - }; - - - public: - - static int Oexception_offset() { return o0_offset; }; - static int G3_offset() { return g3_offset; }; - static int G5_offset() { return g5_offset; }; - static OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words); - static void restore_live_registers(MacroAssembler* masm); - - // During deoptimization only the result register need to be restored - // all the other values have already been extracted. - - static void restore_result_registers(MacroAssembler* masm); -}; - -OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words) { - // Record volatile registers as callee-save values in an OopMap so their save locations will be - // propagated to the caller frame's RegisterMap during StackFrameStream construction (needed for - // deoptimization; see compiledVFrame::create_stack_value). The caller's I, L and O registers - // are saved in register windows - I's and L's in the caller's frame and O's in the stub frame - // (as the stub's I's) when the runtime routine called by the stub creates its frame. - int i; - // Always make the frame size 16 byte aligned. - int frame_size = align_up(additional_frame_words + register_save_size, 16); - // OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words - int frame_size_in_slots = frame_size / sizeof(jint); - // CodeBlob frame size is in words. - *total_frame_words = frame_size / wordSize; - // OopMap* map = new OopMap(*total_frame_words, 0); - OopMap* map = new OopMap(frame_size_in_slots, 0); - - __ save(SP, -frame_size, SP); - - - int debug_offset = 0; - // Save the G's - __ stx(G1, SP, g1_offset+STACK_BIAS); - map->set_callee_saved(VMRegImpl::stack2reg((g1_offset + debug_offset)>>2), G1->as_VMReg()); - - __ stx(G3, SP, g3_offset+STACK_BIAS); - map->set_callee_saved(VMRegImpl::stack2reg((g3_offset + debug_offset)>>2), G3->as_VMReg()); - - __ stx(G4, SP, g4_offset+STACK_BIAS); - map->set_callee_saved(VMRegImpl::stack2reg((g4_offset + debug_offset)>>2), G4->as_VMReg()); - - __ stx(G5, SP, g5_offset+STACK_BIAS); - map->set_callee_saved(VMRegImpl::stack2reg((g5_offset + debug_offset)>>2), G5->as_VMReg()); - - // This is really a waste but we'll keep things as they were for now - if (true) { - } - - - // Save the flags - __ rdccr( G5 ); - __ stx(G5, SP, ccr_offset+STACK_BIAS); - __ stxfsr(SP, fsr_offset+STACK_BIAS); - - // Save all the FP registers: 32 doubles (32 floats correspond to the 2 halves of the first 16 doubles) - int offset = d00_offset; - for( int i=0; iset_callee_saved(VMRegImpl::stack2reg(offset>>2), f->as_VMReg()); - map->set_callee_saved(VMRegImpl::stack2reg((offset + sizeof(float))>>2), f->as_VMReg()->next()); - offset += sizeof(double); - } - - // And we're done. - - return map; -} - - -// Pop the current frame and restore all the registers that we -// saved. -void RegisterSaver::restore_live_registers(MacroAssembler* masm) { - - // Restore all the FP registers - for( int i=0; i 8; -} - -size_t SharedRuntime::trampoline_size() { - return 40; -} - -void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) { - __ set((intptr_t)destination, G3_scratch); - __ JMP(G3_scratch, 0); - __ delayed()->nop(); -} - -// The java_calling_convention describes stack locations as ideal slots on -// a frame with no abi restrictions. Since we must observe abi restrictions -// (like the placement of the register window) the slots must be biased by -// the following value. -static int reg2offset(VMReg r) { - return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; -} - -static VMRegPair reg64_to_VMRegPair(Register r) { - VMRegPair ret; - if (wordSize == 8) { - ret.set2(r->as_VMReg()); - } else { - ret.set_pair(r->successor()->as_VMReg(), r->as_VMReg()); - } - return ret; -} - -// --------------------------------------------------------------------------- -// Read the array of BasicTypes from a signature, and compute where the -// arguments should go. Values in the VMRegPair regs array refer to 4-byte (VMRegImpl::stack_slot_size) -// quantities. Values less than VMRegImpl::stack0 are registers, those above -// refer to 4-byte stack slots. All stack slots are based off of the window -// top. VMRegImpl::stack0 refers to the first slot past the 16-word window, -// and VMRegImpl::stack0+1 refers to the memory word 4-byes higher. Register -// values 0-63 (up to RegisterImpl::number_of_registers) are the 64-bit -// integer registers. Values 64-95 are the (32-bit only) float registers. -// Each 32-bit quantity is given its own number, so the integer registers -// (in either 32- or 64-bit builds) use 2 numbers. For example, there is -// an O0-low and an O0-high. Essentially, all int register numbers are doubled. - -// Register results are passed in O0-O5, for outgoing call arguments. To -// convert to incoming arguments, convert all O's to I's. The regs array -// refer to the low and hi 32-bit words of 64-bit registers or stack slots. -// If the regs[].second() field is set to VMRegImpl::Bad(), it means it's unused (a -// 32-bit value was passed). If both are VMRegImpl::Bad(), it means no value was -// passed (used as a placeholder for the other half of longs and doubles in -// the 64-bit build). regs[].second() is either VMRegImpl::Bad() or regs[].second() is -// regs[].first()+1 (regs[].first() may be misaligned in the C calling convention). -// Sparc never passes a value in regs[].second() but not regs[].first() (regs[].first() -// == VMRegImpl::Bad() && regs[].second() != VMRegImpl::Bad()) nor unrelated values in the -// same VMRegPair. - -// Note: the INPUTS in sig_bt are in units of Java argument words, which are -// either 32-bit or 64-bit depending on the build. The OUTPUTS are in 32-bit -// units regardless of build. - - -// --------------------------------------------------------------------------- -// The compiled Java calling convention. The Java convention always passes -// 64-bit values in adjacent aligned locations (either registers or stack), -// floats in float registers and doubles in aligned float pairs. There is -// no backing varargs store for values in registers. -// In the 32-bit build, longs are passed on the stack (cannot be -// passed in I's, because longs in I's get their heads chopped off at -// interrupt). -int SharedRuntime::java_calling_convention(const BasicType *sig_bt, - VMRegPair *regs, - int total_args_passed, - int is_outgoing) { - assert(F31->as_VMReg()->is_reg(), "overlapping stack/register numbers"); - - const int int_reg_max = SPARC_ARGS_IN_REGS_NUM; - const int flt_reg_max = 8; - - int int_reg = 0; - int flt_reg = 0; - int slot = 0; - - for (int i = 0; i < total_args_passed; i++) { - switch (sig_bt[i]) { - case T_INT: - case T_SHORT: - case T_CHAR: - case T_BYTE: - case T_BOOLEAN: - if (int_reg < int_reg_max) { - Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++); - regs[i].set1(r->as_VMReg()); - } else { - regs[i].set1(VMRegImpl::stack2reg(slot++)); - } - break; - - case T_LONG: - assert((i + 1) < total_args_passed && sig_bt[i+1] == T_VOID, "expecting VOID in other half"); - // fall-through - case T_OBJECT: - case T_ARRAY: - case T_ADDRESS: // Used, e.g., in slow-path locking for the lock's stack address - if (int_reg < int_reg_max) { - Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++); - regs[i].set2(r->as_VMReg()); - } else { - slot = align_up(slot, 2); // align - regs[i].set2(VMRegImpl::stack2reg(slot)); - slot += 2; - } - break; - - case T_FLOAT: - if (flt_reg < flt_reg_max) { - FloatRegister r = as_FloatRegister(flt_reg++); - regs[i].set1(r->as_VMReg()); - } else { - regs[i].set1(VMRegImpl::stack2reg(slot++)); - } - break; - - case T_DOUBLE: - assert((i + 1) < total_args_passed && sig_bt[i+1] == T_VOID, "expecting half"); - if (align_up(flt_reg, 2) + 1 < flt_reg_max) { - flt_reg = align_up(flt_reg, 2); // align - FloatRegister r = as_FloatRegister(flt_reg); - regs[i].set2(r->as_VMReg()); - flt_reg += 2; - } else { - slot = align_up(slot, 2); // align - regs[i].set2(VMRegImpl::stack2reg(slot)); - slot += 2; - } - break; - - case T_VOID: - regs[i].set_bad(); // Halves of longs & doubles - break; - - default: - fatal("unknown basic type %d", sig_bt[i]); - break; - } - } - - // retun the amount of stack space these arguments will need. - return slot; -} - -// Helper class mostly to avoid passing masm everywhere, and handle -// store displacement overflow logic. -class AdapterGenerator { - MacroAssembler *masm; - Register Rdisp; - void set_Rdisp(Register r) { Rdisp = r; } - - void patch_callers_callsite(); - - // base+st_off points to top of argument - int arg_offset(const int st_off) { return st_off; } - int next_arg_offset(const int st_off) { - return st_off - Interpreter::stackElementSize; - } - - // Argument slot values may be loaded first into a register because - // they might not fit into displacement. - RegisterOrConstant arg_slot(const int st_off); - RegisterOrConstant next_arg_slot(const int st_off); - - // Stores long into offset pointed to by base - void store_c2i_long(Register r, Register base, - const int st_off, bool is_stack); - void store_c2i_object(Register r, Register base, - const int st_off); - void store_c2i_int(Register r, Register base, - const int st_off); - void store_c2i_double(VMReg r_2, - VMReg r_1, Register base, const int st_off); - void store_c2i_float(FloatRegister f, Register base, - const int st_off); - - public: - void gen_c2i_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs, - Label& skip_fixup); - void gen_i2c_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs); - - AdapterGenerator(MacroAssembler *_masm) : masm(_masm) {} -}; - - -// Patch the callers callsite with entry to compiled code if it exists. -void AdapterGenerator::patch_callers_callsite() { - Label L; - __ ld_ptr(G5_method, in_bytes(Method::code_offset()), G3_scratch); - __ br_null(G3_scratch, false, Assembler::pt, L); - __ delayed()->nop(); - // Call into the VM to patch the caller, then jump to compiled callee - __ save_frame(4); // Args in compiled layout; do not blow them - - // Must save all the live Gregs the list is: - // G1: 1st Long arg (32bit build) - // G2: global allocated to TLS - // G3: used in inline cache check (scratch) - // G4: 2nd Long arg (32bit build); - // G5: used in inline cache check (Method*) - - // The longs must go to the stack by hand since in the 32 bit build they can be trashed by window ops. - - // mov(s,d) - __ mov(G1, L1); - __ mov(G4, L4); - __ mov(G5_method, L5); - __ mov(G5_method, O0); // VM needs target method - __ mov(I7, O1); // VM needs caller's callsite - // Must be a leaf call... - // can be very far once the blob has been relocated - AddressLiteral dest(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite)); - __ relocate(relocInfo::runtime_call_type); - __ jumpl_to(dest, O7, O7); - __ delayed()->mov(G2_thread, L7_thread_cache); - __ mov(L7_thread_cache, G2_thread); - __ mov(L1, G1); - __ mov(L4, G4); - __ mov(L5, G5_method); - - __ restore(); // Restore args - __ bind(L); -} - - -RegisterOrConstant AdapterGenerator::arg_slot(const int st_off) { - RegisterOrConstant roc(arg_offset(st_off)); - return __ ensure_simm13_or_reg(roc, Rdisp); -} - -RegisterOrConstant AdapterGenerator::next_arg_slot(const int st_off) { - RegisterOrConstant roc(next_arg_offset(st_off)); - return __ ensure_simm13_or_reg(roc, Rdisp); -} - - -// Stores long into offset pointed to by base -void AdapterGenerator::store_c2i_long(Register r, Register base, - const int st_off, bool is_stack) { - // In V9, longs are given 2 64-bit slots in the interpreter, but the - // data is passed in only 1 slot. - __ stx(r, base, next_arg_slot(st_off)); -} - -void AdapterGenerator::store_c2i_object(Register r, Register base, - const int st_off) { - __ st_ptr (r, base, arg_slot(st_off)); -} - -void AdapterGenerator::store_c2i_int(Register r, Register base, - const int st_off) { - __ st (r, base, arg_slot(st_off)); -} - -// Stores into offset pointed to by base -void AdapterGenerator::store_c2i_double(VMReg r_2, - VMReg r_1, Register base, const int st_off) { - // In V9, doubles are given 2 64-bit slots in the interpreter, but the - // data is passed in only 1 slot. - __ stf(FloatRegisterImpl::D, r_1->as_FloatRegister(), base, next_arg_slot(st_off)); -} - -void AdapterGenerator::store_c2i_float(FloatRegister f, Register base, - const int st_off) { - __ stf(FloatRegisterImpl::S, f, base, arg_slot(st_off)); -} - -void AdapterGenerator::gen_c2i_adapter( - int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs, - Label& L_skip_fixup) { - - // Before we get into the guts of the C2I adapter, see if we should be here - // at all. We've come from compiled code and are attempting to jump to the - // interpreter, which means the caller made a static call to get here - // (vcalls always get a compiled target if there is one). Check for a - // compiled target. If there is one, we need to patch the caller's call. - // However we will run interpreted if we come thru here. The next pass - // thru the call site will run compiled. If we ran compiled here then - // we can (theorectically) do endless i2c->c2i->i2c transitions during - // deopt/uncommon trap cycles. If we always go interpreted here then - // we can have at most one and don't need to play any tricks to keep - // from endlessly growing the stack. - // - // Actually if we detected that we had an i2c->c2i transition here we - // ought to be able to reset the world back to the state of the interpreted - // call and not bother building another interpreter arg area. We don't - // do that at this point. - - patch_callers_callsite(); - - __ bind(L_skip_fixup); - - // Since all args are passed on the stack, total_args_passed*wordSize is the - // space we need. Add in varargs area needed by the interpreter. Round up - // to stack alignment. - const int arg_size = total_args_passed * Interpreter::stackElementSize; - const int varargs_area = - (frame::varargs_offset - frame::register_save_words)*wordSize; - const int extraspace = align_up(arg_size + varargs_area, 2*wordSize); - - const int bias = STACK_BIAS; - const int interp_arg_offset = frame::varargs_offset*wordSize + - (total_args_passed-1)*Interpreter::stackElementSize; - - const Register base = SP; - - // Make some extra space on the stack. - __ sub(SP, __ ensure_simm13_or_reg(extraspace, G3_scratch), SP); - set_Rdisp(G3_scratch); - - // Write the args into the outgoing interpreter space. - for (int i = 0; i < total_args_passed; i++) { - const int st_off = interp_arg_offset - (i*Interpreter::stackElementSize) + bias; - VMReg r_1 = regs[i].first(); - VMReg r_2 = regs[i].second(); - if (!r_1->is_valid()) { - assert(!r_2->is_valid(), ""); - continue; - } - if (r_1->is_stack()) { // Pretend stack targets are loaded into G1 - RegisterOrConstant ld_off = reg2offset(r_1) + extraspace + bias; - ld_off = __ ensure_simm13_or_reg(ld_off, Rdisp); - r_1 = G1_scratch->as_VMReg();// as part of the load/store shuffle - if (!r_2->is_valid()) __ ld (base, ld_off, G1_scratch); - else __ ldx(base, ld_off, G1_scratch); - } - - if (r_1->is_Register()) { - Register r = r_1->as_Register()->after_restore(); - if (is_reference_type(sig_bt[i])) { - store_c2i_object(r, base, st_off); - } else if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { - store_c2i_long(r, base, st_off, r_2->is_stack()); - } else { - store_c2i_int(r, base, st_off); - } - } else { - assert(r_1->is_FloatRegister(), ""); - if (sig_bt[i] == T_FLOAT) { - store_c2i_float(r_1->as_FloatRegister(), base, st_off); - } else { - assert(sig_bt[i] == T_DOUBLE, "wrong type"); - store_c2i_double(r_2, r_1, base, st_off); - } - } - } - - // Load the interpreter entry point. - __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), G3_scratch); - - // Pass O5_savedSP as an argument to the interpreter. - // The interpreter will restore SP to this value before returning. - __ add(SP, __ ensure_simm13_or_reg(extraspace, G1), O5_savedSP); - - __ mov((frame::varargs_offset)*wordSize - - 1*Interpreter::stackElementSize+bias+BytesPerWord, G1); - // Jump to the interpreter just as if interpreter was doing it. - __ jmpl(G3_scratch, 0, G0); - // Setup Lesp for the call. Cannot actually set Lesp as the current Lesp - // (really L0) is in use by the compiled frame as a generic temp. However, - // the interpreter does not know where its args are without some kind of - // arg pointer being passed in. Pass it in Gargs. - __ delayed()->add(SP, G1, Gargs); -} - -static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg, Register temp2_reg, - address code_start, address code_end, - Label& L_ok) { - Label L_fail; - __ set(ExternalAddress(code_start), temp_reg); - __ set(pointer_delta(code_end, code_start, 1), temp2_reg); - __ cmp(pc_reg, temp_reg); - __ brx(Assembler::lessEqualUnsigned, false, Assembler::pn, L_fail); - __ delayed()->add(temp_reg, temp2_reg, temp_reg); - __ cmp(pc_reg, temp_reg); - __ cmp_and_brx_short(pc_reg, temp_reg, Assembler::lessUnsigned, Assembler::pt, L_ok); - __ bind(L_fail); -} - -void AdapterGenerator::gen_i2c_adapter(int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs) { - // Generate an I2C adapter: adjust the I-frame to make space for the C-frame - // layout. Lesp was saved by the calling I-frame and will be restored on - // return. Meanwhile, outgoing arg space is all owned by the callee - // C-frame, so we can mangle it at will. After adjusting the frame size, - // hoist register arguments and repack other args according to the compiled - // code convention. Finally, end in a jump to the compiled code. The entry - // point address is the start of the buffer. - - // We will only enter here from an interpreted frame and never from after - // passing thru a c2i. Azul allowed this but we do not. If we lose the - // race and use a c2i we will remain interpreted for the race loser(s). - // This removes all sorts of headaches on the x86 side and also eliminates - // the possibility of having c2i -> i2c -> c2i -> ... endless transitions. - - // More detail: - // Adapters can be frameless because they do not require the caller - // to perform additional cleanup work, such as correcting the stack pointer. - // An i2c adapter is frameless because the *caller* frame, which is interpreted, - // routinely repairs its own stack pointer (from interpreter_frame_last_sp), - // even if a callee has modified the stack pointer. - // A c2i adapter is frameless because the *callee* frame, which is interpreted, - // routinely repairs its caller's stack pointer (from sender_sp, which is set - // up via the senderSP register). - // In other words, if *either* the caller or callee is interpreted, we can - // get the stack pointer repaired after a call. - // This is why c2i and i2c adapters cannot be indefinitely composed. - // In particular, if a c2i adapter were to somehow call an i2c adapter, - // both caller and callee would be compiled methods, and neither would - // clean up the stack pointer changes performed by the two adapters. - // If this happens, control eventually transfers back to the compiled - // caller, but with an uncorrected stack, causing delayed havoc. - - if (VerifyAdapterCalls && - (Interpreter::code() != NULL || StubRoutines::code1() != NULL)) { - // So, let's test for cascading c2i/i2c adapters right now. - // assert(Interpreter::contains($return_addr) || - // StubRoutines::contains($return_addr), - // "i2c adapter must return to an interpreter frame"); - __ block_comment("verify_i2c { "); - Label L_ok; - if (Interpreter::code() != NULL) - range_check(masm, O7, O0, O1, - Interpreter::code()->code_start(), Interpreter::code()->code_end(), - L_ok); - if (StubRoutines::code1() != NULL) - range_check(masm, O7, O0, O1, - StubRoutines::code1()->code_begin(), StubRoutines::code1()->code_end(), - L_ok); - if (StubRoutines::code2() != NULL) - range_check(masm, O7, O0, O1, - StubRoutines::code2()->code_begin(), StubRoutines::code2()->code_end(), - L_ok); - const char* msg = "i2c adapter must return to an interpreter frame"; - __ block_comment(msg); - __ stop(msg); - __ bind(L_ok); - __ block_comment("} verify_i2ce "); - } - - // As you can see from the list of inputs & outputs there are not a lot - // of temp registers to work with: mostly G1, G3 & G4. - - // Inputs: - // G2_thread - TLS - // G5_method - Method oop - // G4 (Gargs) - Pointer to interpreter's args - // O0..O4 - free for scratch - // O5_savedSP - Caller's saved SP, to be restored if needed - // O6 - Current SP! - // O7 - Valid return address - // L0-L7, I0-I7 - Caller's temps (no frame pushed yet) - - // Outputs: - // G2_thread - TLS - // O0-O5 - Outgoing args in compiled layout - // O6 - Adjusted or restored SP - // O7 - Valid return address - // L0-L7, I0-I7 - Caller's temps (no frame pushed yet) - // F0-F7 - more outgoing args - - - // Gargs is the incoming argument base, and also an outgoing argument. - __ sub(Gargs, BytesPerWord, Gargs); - - // ON ENTRY TO THE CODE WE ARE MAKING, WE HAVE AN INTERPRETED FRAME - // WITH O7 HOLDING A VALID RETURN PC - // - // | | - // : java stack : - // | | - // +--------------+ <--- start of outgoing args - // | receiver | | - // : rest of args : |---size is java-arg-words - // | | | - // +--------------+ <--- O4_args (misaligned) and Lesp if prior is not C2I - // | | | - // : unused : |---Space for max Java stack, plus stack alignment - // | | | - // +--------------+ <--- SP + 16*wordsize - // | | - // : window : - // | | - // +--------------+ <--- SP - - // WE REPACK THE STACK. We use the common calling convention layout as - // discovered by calling SharedRuntime::calling_convention. We assume it - // causes an arbitrary shuffle of memory, which may require some register - // temps to do the shuffle. We hope for (and optimize for) the case where - // temps are not needed. We may have to resize the stack slightly, in case - // we need alignment padding (32-bit interpreter can pass longs & doubles - // misaligned, but the compilers expect them aligned). - // - // | | - // : java stack : - // | | - // +--------------+ <--- start of outgoing args - // | pad, align | | - // +--------------+ | - // | ints, longs, | | - // | floats, | |---Outgoing stack args. - // : doubles : | First few args in registers. - // | | | - // +--------------+ <--- SP' + 16*wordsize - // | | - // : window : - // | | - // +--------------+ <--- SP' - - // ON EXIT FROM THE CODE WE ARE MAKING, WE STILL HAVE AN INTERPRETED FRAME - // WITH O7 HOLDING A VALID RETURN PC - ITS JUST THAT THE ARGS ARE NOW SETUP - // FOR COMPILED CODE AND THE FRAME SLIGHTLY GROWN. - - // Cut-out for having no stack args. Since up to 6 args are passed - // in registers, we will commonly have no stack args. - if (comp_args_on_stack > 0) { - // Convert VMReg stack slots to words. - int comp_words_on_stack = align_up(comp_args_on_stack*VMRegImpl::stack_slot_size, wordSize)>>LogBytesPerWord; - // Round up to miminum stack alignment, in wordSize - comp_words_on_stack = align_up(comp_words_on_stack, 2); - // Now compute the distance from Lesp to SP. This calculation does not - // include the space for total_args_passed because Lesp has not yet popped - // the arguments. - __ sub(SP, (comp_words_on_stack)*wordSize, SP); - } - - // Now generate the shuffle code. Pick up all register args and move the - // rest through G1_scratch. - for (int i = 0; i < total_args_passed; i++) { - if (sig_bt[i] == T_VOID) { - // Longs and doubles are passed in native word order, but misaligned - // in the 32-bit build. - assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half"); - continue; - } - - // Pick up 0, 1 or 2 words from Lesp+offset. Assume mis-aligned in the - // 32-bit build and aligned in the 64-bit build. Look for the obvious - // ldx/lddf optimizations. - - // Load in argument order going down. - const int ld_off = (total_args_passed-i)*Interpreter::stackElementSize; - set_Rdisp(G1_scratch); - - VMReg r_1 = regs[i].first(); - VMReg r_2 = regs[i].second(); - if (!r_1->is_valid()) { - assert(!r_2->is_valid(), ""); - continue; - } - if (r_1->is_stack()) { // Pretend stack targets are loaded into F8/F9 - r_1 = F8->as_VMReg(); // as part of the load/store shuffle - if (r_2->is_valid()) r_2 = r_1->next(); - } - if (r_1->is_Register()) { // Register argument - Register r = r_1->as_Register()->after_restore(); - if (!r_2->is_valid()) { - __ ld(Gargs, arg_slot(ld_off), r); - } else { - // In V9, longs are given 2 64-bit slots in the interpreter, but the - // data is passed in only 1 slot. - RegisterOrConstant slot = (sig_bt[i] == T_LONG) ? - next_arg_slot(ld_off) : arg_slot(ld_off); - __ ldx(Gargs, slot, r); - } - } else { - assert(r_1->is_FloatRegister(), ""); - if (!r_2->is_valid()) { - __ ldf(FloatRegisterImpl::S, Gargs, arg_slot(ld_off), r_1->as_FloatRegister()); - } else { - // In V9, doubles are given 2 64-bit slots in the interpreter, but the - // data is passed in only 1 slot. This code also handles longs that - // are passed on the stack, but need a stack-to-stack move through a - // spare float register. - RegisterOrConstant slot = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ? - next_arg_slot(ld_off) : arg_slot(ld_off); - __ ldf(FloatRegisterImpl::D, Gargs, slot, r_1->as_FloatRegister()); - } - } - // Was the argument really intended to be on the stack, but was loaded - // into F8/F9? - if (regs[i].first()->is_stack()) { - assert(r_1->as_FloatRegister() == F8, "fix this code"); - // Convert stack slot to an SP offset - int st_off = reg2offset(regs[i].first()) + STACK_BIAS; - // Store down the shuffled stack word. Target address _is_ aligned. - RegisterOrConstant slot = __ ensure_simm13_or_reg(st_off, Rdisp); - if (!r_2->is_valid()) __ stf(FloatRegisterImpl::S, r_1->as_FloatRegister(), SP, slot); - else __ stf(FloatRegisterImpl::D, r_1->as_FloatRegister(), SP, slot); - } - } - - // Jump to the compiled code just as if compiled code was doing it. - __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3); -#if INCLUDE_JVMCI - if (EnableJVMCI) { - // check if this call should be routed towards a specific entry point - __ ld(Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())), G1); - __ cmp(G0, G1); - Label no_alternative_target; - __ br(Assembler::equal, false, Assembler::pn, no_alternative_target); - __ delayed()->nop(); - - __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()), G3); - __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_alternate_call_target_offset()))); - - __ bind(no_alternative_target); - } -#endif // INCLUDE_JVMCI - - // 6243940 We might end up in handle_wrong_method if - // the callee is deoptimized as we race thru here. If that - // happens we don't want to take a safepoint because the - // caller frame will look interpreted and arguments are now - // "compiled" so it is much better to make this transition - // invisible to the stack walking code. Unfortunately if - // we try and find the callee by normal means a safepoint - // is possible. So we stash the desired callee in the thread - // and the vm will find there should this case occur. - Address callee_target_addr(G2_thread, JavaThread::callee_target_offset()); - __ st_ptr(G5_method, callee_target_addr); - __ jmpl(G3, 0, G0); - __ delayed()->nop(); -} - -void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs) { - AdapterGenerator agen(masm); - agen.gen_i2c_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs); -} - -// --------------------------------------------------------------- -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - // VMReg max_arg, - int comp_args_on_stack, // VMRegStackSlots - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { - address i2c_entry = __ pc(); - - gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); - - - // ------------------------------------------------------------------------- - // Generate a C2I adapter. On entry we know G5 holds the Method*. The - // args start out packed in the compiled layout. They need to be unpacked - // into the interpreter layout. This will almost always require some stack - // space. We grow the current (compiled) stack, then repack the args. We - // finally end in a jump to the generic interpreter entry point. On exit - // from the interpreter, the interpreter will restore our SP (lest the - // compiled code, which relys solely on SP and not FP, get sick). - - address c2i_unverified_entry = __ pc(); - Label L_skip_fixup; - { - Register R_temp = G1; // another scratch register - - AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub()); - - __ verify_oop(O0); - __ load_klass(O0, G3_scratch); - - __ ld_ptr(G5_method, CompiledICHolder::holder_klass_offset(), R_temp); - __ cmp(G3_scratch, R_temp); - - Label ok, ok2; - __ brx(Assembler::equal, false, Assembler::pt, ok); - __ delayed()->ld_ptr(G5_method, CompiledICHolder::holder_metadata_offset(), G5_method); - __ jump_to(ic_miss, G3_scratch); - __ delayed()->nop(); - - __ bind(ok); - // Method might have been compiled since the call site was patched to - // interpreted if that is the case treat it as a miss so we can get - // the call site corrected. - __ ld_ptr(G5_method, in_bytes(Method::code_offset()), G3_scratch); - __ bind(ok2); - __ br_null(G3_scratch, false, Assembler::pt, L_skip_fixup); - __ delayed()->nop(); - __ jump_to(ic_miss, G3_scratch); - __ delayed()->nop(); - - } - - address c2i_entry = __ pc(); - AdapterGenerator agen(masm); - agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup); - - __ flush(); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); - -} - -// Helper function for native calling conventions -static VMReg int_stk_helper( int i ) { - // Bias any stack based VMReg we get by ignoring the window area - // but not the register parameter save area. - // - // This is strange for the following reasons. We'd normally expect - // the calling convention to return an VMReg for a stack slot - // completely ignoring any abi reserved area. C2 thinks of that - // abi area as only out_preserve_stack_slots. This does not include - // the area allocated by the C abi to store down integer arguments - // because the java calling convention does not use it. So - // since c2 assumes that there are only out_preserve_stack_slots - // to bias the optoregs (which impacts VMRegs) when actually referencing any actual stack - // location the c calling convention must add in this bias amount - // to make up for the fact that the out_preserve_stack_slots is - // insufficient for C calls. What a mess. I sure hope those 6 - // stack words were worth it on every java call! - - // Another way of cleaning this up would be for out_preserve_stack_slots - // to take a parameter to say whether it was C or java calling conventions. - // Then things might look a little better (but not much). - - int mem_parm_offset = i - SPARC_ARGS_IN_REGS_NUM; - if( mem_parm_offset < 0 ) { - return as_oRegister(i)->as_VMReg(); - } else { - int actual_offset = (mem_parm_offset + frame::memory_parameter_word_sp_offset) * VMRegImpl::slots_per_word; - // Now return a biased offset that will be correct when out_preserve_slots is added back in - return VMRegImpl::stack2reg(actual_offset - SharedRuntime::out_preserve_stack_slots()); - } -} - - -int SharedRuntime::c_calling_convention(const BasicType *sig_bt, - VMRegPair *regs, - VMRegPair *regs2, - int total_args_passed) { - assert(regs2 == NULL, "not needed on sparc"); - - // Return the number of VMReg stack_slots needed for the args. - // This value does not include an abi space (like register window - // save area). - - // The native convention is V8 if !LP64 - // The LP64 convention is the V9 convention which is slightly more sane. - - // We return the amount of VMReg stack slots we need to reserve for all - // the arguments NOT counting out_preserve_stack_slots. Since we always - // have space for storing at least 6 registers to memory we start with that. - // See int_stk_helper for a further discussion. - int max_stack_slots = (frame::varargs_offset * VMRegImpl::slots_per_word) - SharedRuntime::out_preserve_stack_slots(); - - // V9 convention: All things "as-if" on double-wide stack slots. - // Hoist any int/ptr/long's in the first 6 to int regs. - // Hoist any flt/dbl's in the first 16 dbl regs. - int j = 0; // Count of actual args, not HALVES - VMRegPair param_array_reg; // location of the argument in the parameter array - for (int i = 0; i < total_args_passed; i++, j++) { - param_array_reg.set_bad(); - switch (sig_bt[i]) { - case T_BOOLEAN: - case T_BYTE: - case T_CHAR: - case T_INT: - case T_SHORT: - regs[i].set1(int_stk_helper(j)); - break; - case T_LONG: - assert((i + 1) < total_args_passed && sig_bt[i+1] == T_VOID, "expecting half"); - case T_ADDRESS: // raw pointers, like current thread, for VM calls - case T_ARRAY: - case T_OBJECT: - case T_METADATA: - regs[i].set2(int_stk_helper(j)); - break; - case T_FLOAT: - // Per SPARC Compliance Definition 2.4.1, page 3P-12 available here - // http://www.sparc.org/wp-content/uploads/2014/01/SCD.2.4.1.pdf.gz - // - // "When a callee prototype exists, and does not indicate variable arguments, - // floating-point values assigned to locations %sp+BIAS+128 through %sp+BIAS+248 - // will be promoted to floating-point registers" - // - // By "promoted" it means that the argument is located in two places, an unused - // spill slot in the "parameter array" (starts at %sp+BIAS+128), and a live - // float register. In most cases, there are 6 or fewer arguments of any type, - // and the standard parameter array slots (%sp+BIAS+128 to %sp+BIAS+176 exclusive) - // serve as shadow slots. Per the spec floating point registers %d6 to %d16 - // require slots beyond that (up to %sp+BIAS+248). - // - { - // V9ism: floats go in ODD registers and stack slots - int float_index = 1 + (j << 1); - param_array_reg.set1(VMRegImpl::stack2reg(float_index)); - if (j < 16) { - regs[i].set1(as_FloatRegister(float_index)->as_VMReg()); - } else { - regs[i] = param_array_reg; - } - } - break; - case T_DOUBLE: - { - assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); - // V9ism: doubles go in EVEN/ODD regs and stack slots - int double_index = (j << 1); - param_array_reg.set2(VMRegImpl::stack2reg(double_index)); - if (j < 16) { - regs[i].set2(as_FloatRegister(double_index)->as_VMReg()); - } else { - // V9ism: doubles go in EVEN/ODD stack slots - regs[i] = param_array_reg; - } - } - break; - case T_VOID: - regs[i].set_bad(); - j--; - break; // Do not count HALVES - default: - ShouldNotReachHere(); - } - // Keep track of the deepest parameter array slot. - if (!param_array_reg.first()->is_valid()) { - param_array_reg = regs[i]; - } - if (param_array_reg.first()->is_stack()) { - int off = param_array_reg.first()->reg2stack(); - if (off > max_stack_slots) max_stack_slots = off; - } - if (param_array_reg.second()->is_stack()) { - int off = param_array_reg.second()->reg2stack(); - if (off > max_stack_slots) max_stack_slots = off; - } - } - return align_up(max_stack_slots + 1, 2); - -} - - -// --------------------------------------------------------------------------- -void SharedRuntime::save_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) { - switch (ret_type) { - case T_FLOAT: - __ stf(FloatRegisterImpl::S, F0, SP, frame_slots*VMRegImpl::stack_slot_size - 4+STACK_BIAS); - break; - case T_DOUBLE: - __ stf(FloatRegisterImpl::D, F0, SP, frame_slots*VMRegImpl::stack_slot_size - 8+STACK_BIAS); - break; - } -} - -void SharedRuntime::restore_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) { - switch (ret_type) { - case T_FLOAT: - __ ldf(FloatRegisterImpl::S, SP, frame_slots*VMRegImpl::stack_slot_size - 4+STACK_BIAS, F0); - break; - case T_DOUBLE: - __ ldf(FloatRegisterImpl::D, SP, frame_slots*VMRegImpl::stack_slot_size - 8+STACK_BIAS, F0); - break; - } -} - -// Check and forward and pending exception. Thread is stored in -// L7_thread_cache and possibly NOT in G2_thread. Since this is a native call, there -// is no exception handler. We merely pop this frame off and throw the -// exception in the caller's frame. -static void check_forward_pending_exception(MacroAssembler *masm, Register Rex_oop) { - Label L; - __ br_null(Rex_oop, false, Assembler::pt, L); - __ delayed()->mov(L7_thread_cache, G2_thread); // restore in case we have exception - // Since this is a native call, we *know* the proper exception handler - // without calling into the VM: it's the empty function. Just pop this - // frame and then jump to forward_exception_entry; O7 will contain the - // native caller's return PC. - AddressLiteral exception_entry(StubRoutines::forward_exception_entry()); - __ jump_to(exception_entry, G3_scratch); - __ delayed()->restore(); // Pop this frame off. - __ bind(L); -} - -// A simple move of integer like type -static void simple_move32(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - if (src.first()->is_stack()) { - if (dst.first()->is_stack()) { - // stack to stack - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5); - __ st(L5, SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - // stack to reg - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - } - } else if (dst.first()->is_stack()) { - // reg to stack - __ st(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); - } -} - -// On 64 bit we will store integer like items to the stack as -// 64 bits items (sparc abi) even though java would only store -// 32bits for a parameter. On 32bit it will simply be 32 bits -// So this routine will do 32->32 on 32bit and 32->64 on 64bit -static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - if (src.first()->is_stack()) { - if (dst.first()->is_stack()) { - // stack to stack - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5); - __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - // stack to reg - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - } - } else if (dst.first()->is_stack()) { - // reg to stack - // Some compilers (gcc) expect a clean 32 bit value on function entry - __ signx(src.first()->as_Register(), L5); - __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - // Some compilers (gcc) expect a clean 32 bit value on function entry - __ signx(src.first()->as_Register(), dst.first()->as_Register()); - } -} - - -static void move_ptr(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - if (src.first()->is_stack()) { - if (dst.first()->is_stack()) { - // stack to stack - __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, L5); - __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - // stack to reg - __ ld_ptr(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - } - } else if (dst.first()->is_stack()) { - // reg to stack - __ st_ptr(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); - } -} - - -// An oop arg. Must pass a handle not the oop itself -static void object_move(MacroAssembler* masm, - OopMap* map, - int oop_handle_offset, - int framesize_in_slots, - VMRegPair src, - VMRegPair dst, - bool is_receiver, - int* receiver_offset) { - - // must pass a handle. First figure out the location we use as a handle - - if (src.first()->is_stack()) { - // Oop is already on the stack - Register rHandle = dst.first()->is_stack() ? L5 : dst.first()->as_Register(); - __ add(FP, reg2offset(src.first()) + STACK_BIAS, rHandle); - __ ld_ptr(rHandle, 0, L4); - __ movr( Assembler::rc_z, L4, G0, rHandle ); - if (dst.first()->is_stack()) { - __ st_ptr(rHandle, SP, reg2offset(dst.first()) + STACK_BIAS); - } - int offset_in_older_frame = src.first()->reg2stack() + SharedRuntime::out_preserve_stack_slots(); - if (is_receiver) { - *receiver_offset = (offset_in_older_frame + framesize_in_slots) * VMRegImpl::stack_slot_size; - } - map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + framesize_in_slots)); - } else { - // Oop is in an input register pass we must flush it to the stack - const Register rOop = src.first()->as_Register(); - const Register rHandle = L5; - int oop_slot = rOop->input_number() * VMRegImpl::slots_per_word + oop_handle_offset; - int offset = oop_slot * VMRegImpl::stack_slot_size; - __ st_ptr(rOop, SP, offset + STACK_BIAS); - if (is_receiver) { - *receiver_offset = offset; - } - map->set_oop(VMRegImpl::stack2reg(oop_slot)); - __ add(SP, offset + STACK_BIAS, rHandle); - __ movr( Assembler::rc_z, rOop, G0, rHandle ); - - if (dst.first()->is_stack()) { - __ st_ptr(rHandle, SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - __ mov(rHandle, dst.first()->as_Register()); - } - } -} - -// A float arg may have to do float reg int reg conversion -static void float_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - assert(!src.second()->is_valid() && !dst.second()->is_valid(), "bad float_move"); - - if (src.first()->is_stack()) { - if (dst.first()->is_stack()) { - // stack to stack the easiest of the bunch - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5); - __ st(L5, SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - // stack to reg - if (dst.first()->is_Register()) { - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - } else { - __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_FloatRegister()); - } - } - } else if (dst.first()->is_stack()) { - // reg to stack - if (src.first()->is_Register()) { - __ st(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); - } else { - __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), SP, reg2offset(dst.first()) + STACK_BIAS); - } - } else { - // reg to reg - if (src.first()->is_Register()) { - if (dst.first()->is_Register()) { - // gpr -> gpr - __ mov(src.first()->as_Register(), dst.first()->as_Register()); - } else { - // gpr -> fpr - __ st(src.first()->as_Register(), FP, -4 + STACK_BIAS); - __ ldf(FloatRegisterImpl::S, FP, -4 + STACK_BIAS, dst.first()->as_FloatRegister()); - } - } else if (dst.first()->is_Register()) { - // fpr -> gpr - __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), FP, -4 + STACK_BIAS); - __ ld(FP, -4 + STACK_BIAS, dst.first()->as_Register()); - } else { - // fpr -> fpr - // In theory these overlap but the ordering is such that this is likely a nop - if ( src.first() != dst.first()) { - __ fmov(FloatRegisterImpl::S, src.first()->as_FloatRegister(), dst.first()->as_FloatRegister()); - } - } - } -} - -static void split_long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - VMRegPair src_lo(src.first()); - VMRegPair src_hi(src.second()); - VMRegPair dst_lo(dst.first()); - VMRegPair dst_hi(dst.second()); - simple_move32(masm, src_lo, dst_lo); - simple_move32(masm, src_hi, dst_hi); -} - -// A long move -static void long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - - // Do the simple ones here else do two int moves - if (src.is_single_phys_reg() ) { - if (dst.is_single_phys_reg()) { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); - } else { - // split src into two separate registers - // Remember hi means hi address or lsw on sparc - // Move msw to lsw - if (dst.second()->is_reg()) { - // MSW -> MSW - __ srax(src.first()->as_Register(), 32, dst.first()->as_Register()); - // Now LSW -> LSW - // this will only move lo -> lo and ignore hi - VMRegPair split(dst.second()); - simple_move32(masm, src, split); - } else { - VMRegPair split(src.first(), L4->as_VMReg()); - // MSW -> MSW (lo ie. first word) - __ srax(src.first()->as_Register(), 32, L4); - split_long_move(masm, split, dst); - } - } - } else if (dst.is_single_phys_reg()) { - if (src.is_adjacent_aligned_on_stack(2)) { - __ ldx(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - } else { - // dst is a single reg. - // Remember lo is low address not msb for stack slots - // and lo is the "real" register for registers - // src is - - VMRegPair split; - - if (src.first()->is_reg()) { - // src.lo (msw) is a reg, src.hi is stk/reg - // we will move: src.hi (LSW) -> dst.lo, src.lo (MSW) -> src.lo [the MSW is in the LSW of the reg] - split.set_pair(dst.first(), src.first()); - } else { - // msw is stack move to L5 - // lsw is stack move to dst.lo (real reg) - // we will move: src.hi (LSW) -> dst.lo, src.lo (MSW) -> L5 - split.set_pair(dst.first(), L5->as_VMReg()); - } - - // src.lo -> src.lo/L5, src.hi -> dst.lo (the real reg) - // msw -> src.lo/L5, lsw -> dst.lo - split_long_move(masm, src, split); - - // So dst now has the low order correct position the - // msw half - __ sllx(split.first()->as_Register(), 32, L5); - - const Register d = dst.first()->as_Register(); - __ or3(L5, d, d); - } - } else { - // For LP64 we can probably do better. - split_long_move(masm, src, dst); - } -} - -// A double move -static void double_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { - - // The painful thing here is that like long_move a VMRegPair might be - // 1: a single physical register - // 2: two physical registers (v8) - // 3: a physical reg [lo] and a stack slot [hi] (v8) - // 4: two stack slots - - // Since src is always a java calling convention we know that the src pair - // is always either all registers or all stack (and aligned?) - - // in a register [lo] and a stack slot [hi] - if (src.first()->is_stack()) { - if (dst.first()->is_stack()) { - // stack to stack the easiest of the bunch - // ought to be a way to do this where if alignment is ok we use ldd/std when possible - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, L5); - __ ld(FP, reg2offset(src.second()) + STACK_BIAS, L4); - __ st(L5, SP, reg2offset(dst.first()) + STACK_BIAS); - __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS); - } else { - // stack to reg - if (dst.second()->is_stack()) { - // stack -> reg, stack -> stack - __ ld(FP, reg2offset(src.second()) + STACK_BIAS, L4); - if (dst.first()->is_Register()) { - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - } else { - __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_FloatRegister()); - } - // This was missing. (very rare case) - __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS); - } else { - // stack -> reg - // Eventually optimize for alignment QQQ - if (dst.first()->is_Register()) { - __ ld(FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_Register()); - __ ld(FP, reg2offset(src.second()) + STACK_BIAS, dst.second()->as_Register()); - } else { - __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.first()) + STACK_BIAS, dst.first()->as_FloatRegister()); - __ ldf(FloatRegisterImpl::S, FP, reg2offset(src.second()) + STACK_BIAS, dst.second()->as_FloatRegister()); - } - } - } - } else if (dst.first()->is_stack()) { - // reg to stack - if (src.first()->is_Register()) { - // Eventually optimize for alignment QQQ - __ st(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); - if (src.second()->is_stack()) { - __ ld(FP, reg2offset(src.second()) + STACK_BIAS, L4); - __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS); - } else { - __ st(src.second()->as_Register(), SP, reg2offset(dst.second()) + STACK_BIAS); - } - } else { - // fpr to stack - if (src.second()->is_stack()) { - ShouldNotReachHere(); - } else { - // Is the stack aligned? - if (reg2offset(dst.first()) & 0x7) { - // No do as pairs - __ stf(FloatRegisterImpl::S, src.first()->as_FloatRegister(), SP, reg2offset(dst.first()) + STACK_BIAS); - __ stf(FloatRegisterImpl::S, src.second()->as_FloatRegister(), SP, reg2offset(dst.second()) + STACK_BIAS); - } else { - __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), SP, reg2offset(dst.first()) + STACK_BIAS); - } - } - } - } else { - // reg to reg - if (src.first()->is_Register()) { - if (dst.first()->is_Register()) { - // gpr -> gpr - __ mov(src.first()->as_Register(), dst.first()->as_Register()); - __ mov(src.second()->as_Register(), dst.second()->as_Register()); - } else { - // gpr -> fpr - // ought to be able to do a single store - __ stx(src.first()->as_Register(), FP, -8 + STACK_BIAS); - __ stx(src.second()->as_Register(), FP, -4 + STACK_BIAS); - // ought to be able to do a single load - __ ldf(FloatRegisterImpl::S, FP, -8 + STACK_BIAS, dst.first()->as_FloatRegister()); - __ ldf(FloatRegisterImpl::S, FP, -4 + STACK_BIAS, dst.second()->as_FloatRegister()); - } - } else if (dst.first()->is_Register()) { - // fpr -> gpr - // ought to be able to do a single store - __ stf(FloatRegisterImpl::D, src.first()->as_FloatRegister(), FP, -8 + STACK_BIAS); - // ought to be able to do a single load - // REMEMBER first() is low address not LSB - __ ld(FP, -8 + STACK_BIAS, dst.first()->as_Register()); - if (dst.second()->is_Register()) { - __ ld(FP, -4 + STACK_BIAS, dst.second()->as_Register()); - } else { - __ ld(FP, -4 + STACK_BIAS, L4); - __ st(L4, SP, reg2offset(dst.second()) + STACK_BIAS); - } - } else { - // fpr -> fpr - // In theory these overlap but the ordering is such that this is likely a nop - if ( src.first() != dst.first()) { - __ fmov(FloatRegisterImpl::D, src.first()->as_FloatRegister(), dst.first()->as_FloatRegister()); - } - } - } -} - -// Creates an inner frame if one hasn't already been created, and -// saves a copy of the thread in L7_thread_cache -static void create_inner_frame(MacroAssembler* masm, bool* already_created) { - if (!*already_created) { - __ save_frame(0); - // Save thread in L7 (INNER FRAME); it crosses a bunch of VM calls below - // Don't use save_thread because it smashes G2 and we merely want to save a - // copy - __ mov(G2_thread, L7_thread_cache); - *already_created = true; - } -} - - -static void save_or_restore_arguments(MacroAssembler* masm, - const int stack_slots, - const int total_in_args, - const int arg_save_area, - OopMap* map, - VMRegPair* in_regs, - BasicType* in_sig_bt) { - // if map is non-NULL then the code should store the values, - // otherwise it should load them. - if (map != NULL) { - // Fill in the map - for (int i = 0; i < total_in_args; i++) { - if (in_sig_bt[i] == T_ARRAY) { - if (in_regs[i].first()->is_stack()) { - int offset_in_older_frame = in_regs[i].first()->reg2stack() + SharedRuntime::out_preserve_stack_slots(); - map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + stack_slots)); - } else if (in_regs[i].first()->is_Register()) { - map->set_oop(in_regs[i].first()); - } else { - ShouldNotReachHere(); - } - } - } - } - - // Save or restore double word values - int handle_index = 0; - for (int i = 0; i < total_in_args; i++) { - int slot = handle_index + arg_save_area; - int offset = slot * VMRegImpl::stack_slot_size; - if (in_sig_bt[i] == T_LONG && in_regs[i].first()->is_Register()) { - const Register reg = in_regs[i].first()->as_Register(); - if (reg->is_global()) { - handle_index += 2; - assert(handle_index <= stack_slots, "overflow"); - if (map != NULL) { - __ stx(reg, SP, offset + STACK_BIAS); - } else { - __ ldx(SP, offset + STACK_BIAS, reg); - } - } - } else if (in_sig_bt[i] == T_DOUBLE && in_regs[i].first()->is_FloatRegister()) { - handle_index += 2; - assert(handle_index <= stack_slots, "overflow"); - if (map != NULL) { - __ stf(FloatRegisterImpl::D, in_regs[i].first()->as_FloatRegister(), SP, offset + STACK_BIAS); - } else { - __ ldf(FloatRegisterImpl::D, SP, offset + STACK_BIAS, in_regs[i].first()->as_FloatRegister()); - } - } - } - // Save floats - for (int i = 0; i < total_in_args; i++) { - int slot = handle_index + arg_save_area; - int offset = slot * VMRegImpl::stack_slot_size; - if (in_sig_bt[i] == T_FLOAT && in_regs[i].first()->is_FloatRegister()) { - handle_index++; - assert(handle_index <= stack_slots, "overflow"); - if (map != NULL) { - __ stf(FloatRegisterImpl::S, in_regs[i].first()->as_FloatRegister(), SP, offset + STACK_BIAS); - } else { - __ ldf(FloatRegisterImpl::S, SP, offset + STACK_BIAS, in_regs[i].first()->as_FloatRegister()); - } - } - } - -} - - -// Check GCLocker::needs_gc and enter the runtime if it's true. This -// keeps a new JNI critical region from starting until a GC has been -// forced. Save down any oops in registers and describe them in an -// OopMap. -static void check_needs_gc_for_critical_native(MacroAssembler* masm, - const int stack_slots, - const int total_in_args, - const int arg_save_area, - OopMapSet* oop_maps, - VMRegPair* in_regs, - BasicType* in_sig_bt) { - __ block_comment("check GCLocker::needs_gc"); - Label cont; - AddressLiteral sync_state(GCLocker::needs_gc_address()); - __ load_bool_contents(sync_state, G3_scratch); - __ cmp_zero_and_br(Assembler::equal, G3_scratch, cont); - __ delayed()->nop(); - - // Save down any values that are live in registers and call into the - // runtime to halt for a GC - OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); - save_or_restore_arguments(masm, stack_slots, total_in_args, - arg_save_area, map, in_regs, in_sig_bt); - - __ mov(G2_thread, L7_thread_cache); - - __ set_last_Java_frame(SP, noreg); - - __ block_comment("block_for_jni_critical"); - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical), relocInfo::runtime_call_type); - __ delayed()->mov(L7_thread_cache, O0); - oop_maps->add_gc_map( __ offset(), map); - - __ restore_thread(L7_thread_cache); // restore G2_thread - __ reset_last_Java_frame(); - - // Reload all the register arguments - save_or_restore_arguments(masm, stack_slots, total_in_args, - arg_save_area, NULL, in_regs, in_sig_bt); - - __ bind(cont); -#ifdef ASSERT - if (StressCriticalJNINatives) { - // Stress register saving - OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); - save_or_restore_arguments(masm, stack_slots, total_in_args, - arg_save_area, map, in_regs, in_sig_bt); - // Destroy argument registers - for (int i = 0; i < total_in_args; i++) { - if (in_regs[i].first()->is_Register()) { - const Register reg = in_regs[i].first()->as_Register(); - if (reg->is_global()) { - __ mov(G0, reg); - } - } else if (in_regs[i].first()->is_FloatRegister()) { - __ fneg(FloatRegisterImpl::D, in_regs[i].first()->as_FloatRegister(), in_regs[i].first()->as_FloatRegister()); - } - } - - save_or_restore_arguments(masm, stack_slots, total_in_args, - arg_save_area, NULL, in_regs, in_sig_bt); - } -#endif -} - -// Unpack an array argument into a pointer to the body and the length -// if the array is non-null, otherwise pass 0 for both. -static void unpack_array_argument(MacroAssembler* masm, VMRegPair reg, BasicType in_elem_type, VMRegPair body_arg, VMRegPair length_arg) { - // Pass the length, ptr pair - Label is_null, done; - if (reg.first()->is_stack()) { - VMRegPair tmp = reg64_to_VMRegPair(L2); - // Load the arg up from the stack - move_ptr(masm, reg, tmp); - reg = tmp; - } - __ cmp(reg.first()->as_Register(), G0); - __ brx(Assembler::equal, false, Assembler::pt, is_null); - __ delayed()->add(reg.first()->as_Register(), arrayOopDesc::base_offset_in_bytes(in_elem_type), L4); - move_ptr(masm, reg64_to_VMRegPair(L4), body_arg); - __ ld(reg.first()->as_Register(), arrayOopDesc::length_offset_in_bytes(), L4); - move32_64(masm, reg64_to_VMRegPair(L4), length_arg); - __ ba_short(done); - __ bind(is_null); - // Pass zeros - move_ptr(masm, reg64_to_VMRegPair(G0), body_arg); - move32_64(masm, reg64_to_VMRegPair(G0), length_arg); - __ bind(done); -} - -static void verify_oop_args(MacroAssembler* masm, - const methodHandle& method, - const BasicType* sig_bt, - const VMRegPair* regs) { - Register temp_reg = G5_method; // not part of any compiled calling seq - if (VerifyOops) { - for (int i = 0; i < method->size_of_parameters(); i++) { - if (is_reference_type(sig_bt[i])) { - VMReg r = regs[i].first(); - assert(r->is_valid(), "bad oop arg"); - if (r->is_stack()) { - RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS; - ld_off = __ ensure_simm13_or_reg(ld_off, temp_reg); - __ ld_ptr(SP, ld_off, temp_reg); - __ verify_oop(temp_reg); - } else { - __ verify_oop(r->as_Register()); - } - } - } - } -} - -static void gen_special_dispatch(MacroAssembler* masm, - const methodHandle& method, - const BasicType* sig_bt, - const VMRegPair* regs) { - verify_oop_args(masm, method, sig_bt, regs); - vmIntrinsics::ID iid = method->intrinsic_id(); - - // Now write the args into the outgoing interpreter space - bool has_receiver = false; - Register receiver_reg = noreg; - int member_arg_pos = -1; - Register member_reg = noreg; - int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid); - if (ref_kind != 0) { - member_arg_pos = method->size_of_parameters() - 1; // trailing MemberName argument - member_reg = G5_method; // known to be free at this point - has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind); - } else if (iid == vmIntrinsics::_invokeBasic) { - has_receiver = true; - } else { - fatal("unexpected intrinsic id %d", iid); - } - - if (member_reg != noreg) { - // Load the member_arg into register, if necessary. - SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs); - VMReg r = regs[member_arg_pos].first(); - if (r->is_stack()) { - RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS; - ld_off = __ ensure_simm13_or_reg(ld_off, member_reg); - __ ld_ptr(SP, ld_off, member_reg); - } else { - // no data motion is needed - member_reg = r->as_Register(); - } - } - - if (has_receiver) { - // Make sure the receiver is loaded into a register. - assert(method->size_of_parameters() > 0, "oob"); - assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object"); - VMReg r = regs[0].first(); - assert(r->is_valid(), "bad receiver arg"); - if (r->is_stack()) { - // Porting note: This assumes that compiled calling conventions always - // pass the receiver oop in a register. If this is not true on some - // platform, pick a temp and load the receiver from stack. - fatal("receiver always in a register"); - receiver_reg = G3_scratch; // known to be free at this point - RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS; - ld_off = __ ensure_simm13_or_reg(ld_off, member_reg); - __ ld_ptr(SP, ld_off, receiver_reg); - } else { - // no data motion is needed - receiver_reg = r->as_Register(); - } - } - - // Figure out which address we are really jumping to: - MethodHandles::generate_method_handle_dispatch(masm, iid, - receiver_reg, member_reg, /*for_compiler_entry:*/ true); -} - -// --------------------------------------------------------------------------- -// Generate a native wrapper for a given method. The method takes arguments -// in the Java compiled code convention, marshals them to the native -// convention (handlizes oops, etc), transitions to native, makes the call, -// returns to java state (possibly blocking), unhandlizes any result and -// returns. -// -// Critical native functions are a shorthand for the use of -// GetPrimtiveArrayCritical and disallow the use of any other JNI -// functions. The wrapper is expected to unpack the arguments before -// passing them to the callee and perform checks before and after the -// native call to ensure that they GCLocker -// lock_critical/unlock_critical semantics are followed. Some other -// parts of JNI setup are skipped like the tear down of the JNI handle -// block and the check for pending exceptions it's impossible for them -// to be thrown. -// -// They are roughly structured like this: -// if (GCLocker::needs_gc()) -// SharedRuntime::block_for_jni_critical(); -// tranistion to thread_in_native -// unpack arrray arguments and call native entry point -// check for safepoint in progress -// check if any thread suspend flags are set -// call into JVM and possible unlock the JNI critical -// if a GC was suppressed while in the critical native. -// transition back to thread_in_Java -// return to caller -// -nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, - const methodHandle& method, - int compile_id, - BasicType* in_sig_bt, - VMRegPair* in_regs, - BasicType ret_type, - address critical_entry) { - if (method->is_method_handle_intrinsic()) { - vmIntrinsics::ID iid = method->intrinsic_id(); - intptr_t start = (intptr_t)__ pc(); - int vep_offset = ((intptr_t)__ pc()) - start; - gen_special_dispatch(masm, - method, - in_sig_bt, - in_regs); - int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period - __ flush(); - int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually - return nmethod::new_native_nmethod(method, - compile_id, - masm->code(), - vep_offset, - frame_complete, - stack_slots / VMRegImpl::slots_per_word, - in_ByteSize(-1), - in_ByteSize(-1), - (OopMapSet*)NULL); - } - bool is_critical_native = true; - address native_func = critical_entry; - if (native_func == NULL) { - native_func = method->native_function(); - is_critical_native = false; - } - assert(native_func != NULL, "must have function"); - - // Native nmethod wrappers never take possesion of the oop arguments. - // So the caller will gc the arguments. The only thing we need an - // oopMap for is if the call is static - // - // An OopMap for lock (and class if static), and one for the VM call itself - OopMapSet *oop_maps = new OopMapSet(); - intptr_t start = (intptr_t)__ pc(); - - // First thing make an ic check to see if we should even be here - { - Label L; - const Register temp_reg = G3_scratch; - AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub()); - __ verify_oop(O0); - __ load_klass(O0, temp_reg); - __ cmp_and_brx_short(temp_reg, G5_inline_cache_reg, Assembler::equal, Assembler::pt, L); - - __ jump_to(ic_miss, temp_reg); - __ delayed()->nop(); - __ align(CodeEntryAlignment); - __ bind(L); - } - - int vep_offset = ((intptr_t)__ pc()) - start; - -#ifdef COMPILER1 - if ((InlineObjectHash && method->intrinsic_id() == vmIntrinsics::_hashCode) || (method->intrinsic_id() == vmIntrinsics::_identityHashCode)) { - // Object.hashCode, System.identityHashCode can pull the hashCode from the - // header word instead of doing a full VM transition once it's been computed. - // Since hashCode is usually polymorphic at call sites we can't do this - // optimization at the call site without a lot of work. - Label slowCase; - Label done; - Register obj_reg = O0; - Register result = O0; - Register header = G3_scratch; - Register hash = G3_scratch; // overwrite header value with hash value - Register mask = G1; // to get hash field from header - - // Unlike for Object.hashCode, System.identityHashCode is static method and - // gets object as argument instead of the receiver. - if (method->intrinsic_id() == vmIntrinsics::_identityHashCode) { - assert(method->is_static(), "method should be static"); - // return 0 for null reference input - __ br_null(obj_reg, false, Assembler::pn, done); - __ delayed()->mov(obj_reg, hash); - } - - // Read the header and build a mask to get its hash field. Give up if the object is not unlocked. - // We depend on hash_mask being at most 32 bits and avoid the use of - // hash_mask_in_place because it could be larger than 32 bits in a 64-bit - // vm: see markWord.hpp. - __ ld_ptr(obj_reg, oopDesc::mark_offset_in_bytes(), header); - __ sethi(markWord::hash_mask, mask); - __ btst(markWord::unlocked_value, header); - __ br(Assembler::zero, false, Assembler::pn, slowCase); - if (UseBiasedLocking) { - // Check if biased and fall through to runtime if so - __ delayed()->nop(); - __ btst(markWord::biased_lock_bit_in_place, header); - __ br(Assembler::notZero, false, Assembler::pn, slowCase); - } - __ delayed()->or3(mask, markWord::hash_mask & 0x3ff, mask); - - // Check for a valid (non-zero) hash code and get its value. - __ srlx(header, markWord::hash_shift, hash); - __ andcc(hash, mask, hash); - __ br(Assembler::equal, false, Assembler::pn, slowCase); - __ delayed()->nop(); - - // leaf return. - __ bind(done); - __ retl(); - __ delayed()->mov(hash, result); - __ bind(slowCase); - } -#endif // COMPILER1 - - - // We have received a description of where all the java arg are located - // on entry to the wrapper. We need to convert these args to where - // the jni function will expect them. To figure out where they go - // we convert the java signature to a C signature by inserting - // the hidden arguments as arg[0] and possibly arg[1] (static method) - - const int total_in_args = method->size_of_parameters(); - int total_c_args = total_in_args; - int total_save_slots = 6 * VMRegImpl::slots_per_word; - if (!is_critical_native) { - total_c_args += 1; - if (method->is_static()) { - total_c_args++; - } - } else { - for (int i = 0; i < total_in_args; i++) { - if (in_sig_bt[i] == T_ARRAY) { - // These have to be saved and restored across the safepoint - total_c_args++; - } - } - } - - BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args); - VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_c_args); - BasicType* in_elem_bt = NULL; - - int argc = 0; - if (!is_critical_native) { - out_sig_bt[argc++] = T_ADDRESS; - if (method->is_static()) { - out_sig_bt[argc++] = T_OBJECT; - } - - for (int i = 0; i < total_in_args ; i++ ) { - out_sig_bt[argc++] = in_sig_bt[i]; - } - } else { - Thread* THREAD = Thread::current(); - in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_in_args); - SignatureStream ss(method->signature()); - for (int i = 0; i < total_in_args ; i++ ) { - if (in_sig_bt[i] == T_ARRAY) { - // Arrays are passed as int, elem* pair - out_sig_bt[argc++] = T_INT; - out_sig_bt[argc++] = T_ADDRESS; - ss.skip_array_prefix(1); // skip one '[' - assert(ss.is_primitive(), "primitive type expected"); - in_elem_bt[i] = ss.type(); - } else { - out_sig_bt[argc++] = in_sig_bt[i]; - in_elem_bt[i] = T_VOID; - } - if (in_sig_bt[i] != T_VOID) { - assert(in_sig_bt[i] == ss.type() || - in_sig_bt[i] == T_ARRAY, "must match"); - ss.next(); - } - } - } - - // Now figure out where the args must be stored and how much stack space - // they require (neglecting out_preserve_stack_slots but space for storing - // the 1st six register arguments). It's weird see int_stk_helper. - // - int out_arg_slots; - out_arg_slots = c_calling_convention(out_sig_bt, out_regs, NULL, total_c_args); - - if (is_critical_native) { - // Critical natives may have to call out so they need a save area - // for register arguments. - int double_slots = 0; - int single_slots = 0; - for ( int i = 0; i < total_in_args; i++) { - if (in_regs[i].first()->is_Register()) { - const Register reg = in_regs[i].first()->as_Register(); - switch (in_sig_bt[i]) { - case T_ARRAY: - case T_BOOLEAN: - case T_BYTE: - case T_SHORT: - case T_CHAR: - case T_INT: assert(reg->is_in(), "don't need to save these"); break; - case T_LONG: if (reg->is_global()) double_slots++; break; - default: ShouldNotReachHere(); - } - } else if (in_regs[i].first()->is_FloatRegister()) { - switch (in_sig_bt[i]) { - case T_FLOAT: single_slots++; break; - case T_DOUBLE: double_slots++; break; - default: ShouldNotReachHere(); - } - } - } - total_save_slots = double_slots * 2 + single_slots; - } - - // Compute framesize for the wrapper. We need to handlize all oops in - // registers. We must create space for them here that is disjoint from - // the windowed save area because we have no control over when we might - // flush the window again and overwrite values that gc has since modified. - // (The live window race) - // - // We always just allocate 6 word for storing down these object. This allow - // us to simply record the base and use the Ireg number to decide which - // slot to use. (Note that the reg number is the inbound number not the - // outbound number). - // We must shuffle args to match the native convention, and include var-args space. - - // Calculate the total number of stack slots we will need. - - // First count the abi requirement plus all of the outgoing args - int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; - - // Now the space for the inbound oop handle area - - int oop_handle_offset = align_up(stack_slots, 2); - stack_slots += total_save_slots; - - // Now any space we need for handlizing a klass if static method - - int klass_slot_offset = 0; - int klass_offset = -1; - int lock_slot_offset = 0; - bool is_static = false; - - if (method->is_static()) { - klass_slot_offset = stack_slots; - stack_slots += VMRegImpl::slots_per_word; - klass_offset = klass_slot_offset * VMRegImpl::stack_slot_size; - is_static = true; - } - - // Plus a lock if needed - - if (method->is_synchronized()) { - lock_slot_offset = stack_slots; - stack_slots += VMRegImpl::slots_per_word; - } - - // Now a place to save return value or as a temporary for any gpr -> fpr moves - stack_slots += 2; - - // Ok The space we have allocated will look like: - // - // - // FP-> | | - // |---------------------| - // | 2 slots for moves | - // |---------------------| - // | lock box (if sync) | - // |---------------------| <- lock_slot_offset - // | klass (if static) | - // |---------------------| <- klass_slot_offset - // | oopHandle area | - // |---------------------| <- oop_handle_offset - // | outbound memory | - // | based arguments | - // | | - // |---------------------| - // | vararg area | - // |---------------------| - // | | - // SP-> | out_preserved_slots | - // - // - - - // Now compute actual number of stack words we need rounding to make - // stack properly aligned. - stack_slots = align_up(stack_slots, 2 * VMRegImpl::slots_per_word); - - int stack_size = stack_slots * VMRegImpl::stack_slot_size; - - // Generate stack overflow check before creating frame - __ generate_stack_overflow_check(stack_size); - - // Generate a new frame for the wrapper. - __ save(SP, -stack_size, SP); - - int frame_complete = ((intptr_t)__ pc()) - start; - - __ verify_thread(); - - if (is_critical_native) { - check_needs_gc_for_critical_native(masm, stack_slots, total_in_args, - oop_handle_offset, oop_maps, in_regs, in_sig_bt); - } - - // - // We immediately shuffle the arguments so that any vm call we have to - // make from here on out (sync slow path, jvmti, etc.) we will have - // captured the oops from our caller and have a valid oopMap for - // them. - - // ----------------- - // The Grand Shuffle - // - // Natives require 1 or 2 extra arguments over the normal ones: the JNIEnv* - // (derived from JavaThread* which is in L7_thread_cache) and, if static, - // the class mirror instead of a receiver. This pretty much guarantees that - // register layout will not match. We ignore these extra arguments during - // the shuffle. The shuffle is described by the two calling convention - // vectors we have in our possession. We simply walk the java vector to - // get the source locations and the c vector to get the destinations. - // Because we have a new window and the argument registers are completely - // disjoint ( I0 -> O1, I1 -> O2, ...) we have nothing to worry about - // here. - - // This is a trick. We double the stack slots so we can claim - // the oops in the caller's frame. Since we are sure to have - // more args than the caller doubling is enough to make - // sure we can capture all the incoming oop args from the - // caller. - // - OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); - // Record sp-based slot for receiver on stack for non-static methods - int receiver_offset = -1; - - // We move the arguments backward because the floating point registers - // destination will always be to a register with a greater or equal register - // number or the stack. - -#ifdef ASSERT - bool reg_destroyed[RegisterImpl::number_of_registers]; - bool freg_destroyed[FloatRegisterImpl::number_of_registers]; - for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) { - reg_destroyed[r] = false; - } - for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) { - freg_destroyed[f] = false; - } - -#endif /* ASSERT */ - - for ( int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0 ; i--, c_arg-- ) { - -#ifdef ASSERT - if (in_regs[i].first()->is_Register()) { - assert(!reg_destroyed[in_regs[i].first()->as_Register()->encoding()], "ack!"); - } else if (in_regs[i].first()->is_FloatRegister()) { - assert(!freg_destroyed[in_regs[i].first()->as_FloatRegister()->encoding(FloatRegisterImpl::S)], "ack!"); - } - if (out_regs[c_arg].first()->is_Register()) { - reg_destroyed[out_regs[c_arg].first()->as_Register()->encoding()] = true; - } else if (out_regs[c_arg].first()->is_FloatRegister()) { - freg_destroyed[out_regs[c_arg].first()->as_FloatRegister()->encoding(FloatRegisterImpl::S)] = true; - } -#endif /* ASSERT */ - - switch (in_sig_bt[i]) { - case T_ARRAY: - if (is_critical_native) { - unpack_array_argument(masm, in_regs[i], in_elem_bt[i], out_regs[c_arg], out_regs[c_arg - 1]); - c_arg--; - break; - } - case T_OBJECT: - assert(!is_critical_native, "no oop arguments"); - object_move(masm, map, oop_handle_offset, stack_slots, in_regs[i], out_regs[c_arg], - ((i == 0) && (!is_static)), - &receiver_offset); - break; - case T_VOID: - break; - - case T_FLOAT: - float_move(masm, in_regs[i], out_regs[c_arg]); - break; - - case T_DOUBLE: - assert( i + 1 < total_in_args && - in_sig_bt[i + 1] == T_VOID && - out_sig_bt[c_arg+1] == T_VOID, "bad arg list"); - double_move(masm, in_regs[i], out_regs[c_arg]); - break; - - case T_LONG : - long_move(masm, in_regs[i], out_regs[c_arg]); - break; - - case T_ADDRESS: assert(false, "found T_ADDRESS in java args"); - - default: - move32_64(masm, in_regs[i], out_regs[c_arg]); - } - } - - // Pre-load a static method's oop into O1. Used both by locking code and - // the normal JNI call code. - if (method->is_static() && !is_critical_native) { - __ set_oop_constant(JNIHandles::make_local(method->method_holder()->java_mirror()), O1); - - // Now handlize the static class mirror in O1. It's known not-null. - __ st_ptr(O1, SP, klass_offset + STACK_BIAS); - map->set_oop(VMRegImpl::stack2reg(klass_slot_offset)); - __ add(SP, klass_offset + STACK_BIAS, O1); - } - - - const Register L6_handle = L6; - - if (method->is_synchronized()) { - assert(!is_critical_native, "unhandled"); - __ mov(O1, L6_handle); - } - - // We have all of the arguments setup at this point. We MUST NOT touch any Oregs - // except O6/O7. So if we must call out we must push a new frame. We immediately - // push a new frame and flush the windows. - intptr_t thepc = (intptr_t) __ pc(); - { - address here = __ pc(); - // Call the next instruction - __ call(here + 8, relocInfo::none); - __ delayed()->nop(); - } - - // We use the same pc/oopMap repeatedly when we call out - oop_maps->add_gc_map(thepc - start, map); - - // O7 now has the pc loaded that we will use when we finally call to native. - - // Save thread in L7; it crosses a bunch of VM calls below - // Don't use save_thread because it smashes G2 and we merely - // want to save a copy - __ mov(G2_thread, L7_thread_cache); - - - // If we create an inner frame once is plenty - // when we create it we must also save G2_thread - bool inner_frame_created = false; - - // dtrace method entry support - { - SkipIfEqual skip_if( - masm, G3_scratch, &DTraceMethodProbes, Assembler::zero); - // create inner frame - __ save_frame(0); - __ mov(G2_thread, L7_thread_cache); - __ set_metadata_constant(method(), O1); - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), - G2_thread, O1); - __ restore(); - } - - // RedefineClasses() tracing support for obsolete method entry - if (log_is_enabled(Trace, redefine, class, obsolete)) { - // create inner frame - __ save_frame(0); - __ mov(G2_thread, L7_thread_cache); - __ set_metadata_constant(method(), O1); - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), - G2_thread, O1); - __ restore(); - } - - // We are in the jni frame unless saved_frame is true in which case - // we are in one frame deeper (the "inner" frame). If we are in the - // "inner" frames the args are in the Iregs and if the jni frame then - // they are in the Oregs. - // If we ever need to go to the VM (for locking, jvmti) then - // we will always be in the "inner" frame. - - // Lock a synchronized method - int lock_offset = -1; // Set if locked - if (method->is_synchronized()) { - Register Roop = O1; - const Register L3_box = L3; - - create_inner_frame(masm, &inner_frame_created); - - __ ld_ptr(I1, 0, O1); - Label done; - - lock_offset = (lock_slot_offset * VMRegImpl::stack_slot_size); - __ add(FP, lock_offset+STACK_BIAS, L3_box); -#ifdef ASSERT - if (UseBiasedLocking) { - // making the box point to itself will make it clear it went unused - // but also be obviously invalid - __ st_ptr(L3_box, L3_box, 0); - } -#endif // ASSERT - // - // Compiler_lock_object (Roop, Rmark, Rbox, Rscratch) -- kills Rmark, Rbox, Rscratch - // - __ compiler_lock_object(Roop, L1, L3_box, L2); - __ br(Assembler::equal, false, Assembler::pt, done); - __ delayed() -> add(FP, lock_offset+STACK_BIAS, L3_box); - - - // None of the above fast optimizations worked so we have to get into the - // slow case of monitor enter. Inline a special case of call_VM that - // disallows any pending_exception. - __ mov(Roop, O0); // Need oop in O0 - __ mov(L3_box, O1); - - // Record last_Java_sp, in case the VM code releases the JVM lock. - - __ set_last_Java_frame(FP, I7); - - // do the call - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C), relocInfo::runtime_call_type); - __ delayed()->mov(L7_thread_cache, O2); - - __ restore_thread(L7_thread_cache); // restore G2_thread - __ reset_last_Java_frame(); - -#ifdef ASSERT - { Label L; - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O0); - __ br_null_short(O0, Assembler::pt, L); - __ stop("no pending exception allowed on exit from IR::monitorenter"); - __ bind(L); - } -#endif - __ bind(done); - } - - - // Finally just about ready to make the JNI call - - __ flushw(); - if (inner_frame_created) { - __ restore(); - } else { - // Store only what we need from this frame - // QQQ I think that non-v9 (like we care) we don't need these saves - // either as the flush traps and the current window goes too. - __ st_ptr(FP, SP, FP->sp_offset_in_saved_window()*wordSize + STACK_BIAS); - __ st_ptr(I7, SP, I7->sp_offset_in_saved_window()*wordSize + STACK_BIAS); - } - - // get JNIEnv* which is first argument to native - if (!is_critical_native) { - __ add(G2_thread, in_bytes(JavaThread::jni_environment_offset()), O0); - } - - // Use that pc we placed in O7 a while back as the current frame anchor - __ set_last_Java_frame(SP, O7); - - // We flushed the windows ages ago now mark them as flushed before transitioning. - __ set(JavaFrameAnchor::flushed, G3_scratch); - __ st(G3_scratch, G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset()); - - // Transition from _thread_in_Java to _thread_in_native. - __ set(_thread_in_native, G3_scratch); - - AddressLiteral dest(native_func); - __ relocate(relocInfo::runtime_call_type); - __ jumpl_to(dest, O7, O7); - __ delayed()->st(G3_scratch, G2_thread, JavaThread::thread_state_offset()); - - __ restore_thread(L7_thread_cache); // restore G2_thread - - // Unpack native results. For int-types, we do any needed sign-extension - // and move things into I0. The return value there will survive any VM - // calls for blocking or unlocking. An FP or OOP result (handle) is done - // specially in the slow-path code. - switch (ret_type) { - case T_VOID: break; // Nothing to do! - case T_FLOAT: break; // Got it where we want it (unless slow-path) - case T_DOUBLE: break; // Got it where we want it (unless slow-path) - // In 64 bits build result is in O0, in O0, O1 in 32bit build - case T_LONG: - // Fall thru - case T_OBJECT: // Really a handle - case T_ARRAY: - case T_INT: - __ mov(O0, I0); - break; - case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, I0); break; // !0 => true; 0 => false - case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, I0); break; - case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, I0); break; // cannot use and3, 0xFFFF too big as immediate value! - case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, I0); break; - break; // Cannot de-handlize until after reclaiming jvm_lock - default: - ShouldNotReachHere(); - } - - Label after_transition; - // must we block? - - // Block, if necessary, before resuming in _thread_in_Java state. - // In order for GC to work, don't clear the last_Java_sp until after blocking. - { Label no_block; - - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // VM thread changes sync state to synchronizing and suspends threads for GC. - // Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization is progress, and escapes. - __ set(_thread_in_native_trans, G3_scratch); - __ st(G3_scratch, G2_thread, JavaThread::thread_state_offset()); - - // Force this write out before the read below - __ membar(Assembler::StoreLoad); - - Label L; - Address suspend_state(G2_thread, JavaThread::suspend_flags_offset()); - __ safepoint_poll(L, false, G2_thread, G3_scratch); - __ delayed()->ld(suspend_state, G3_scratch); - __ cmp_and_br_short(G3_scratch, 0, Assembler::equal, Assembler::pt, no_block); - __ bind(L); - - // Block. Save any potential method result value before the operation and - // use a leaf call to leave the last_Java_frame setup undisturbed. Doing this - // lets us share the oopMap we used when we went native rather the create - // a distinct one for this pc - // - save_native_result(masm, ret_type, stack_slots); - if (!is_critical_native) { - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), - G2_thread); - } else { - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans_and_transition), - G2_thread); - } - - // Restore any method result value - restore_native_result(masm, ret_type, stack_slots); - - if (is_critical_native) { - // The call above performed the transition to thread_in_Java so - // skip the transition logic below. - __ ba(after_transition); - __ delayed()->nop(); - } - - __ bind(no_block); - } - - // thread state is thread_in_native_trans. Any safepoint blocking has already - // happened so we can now change state to _thread_in_Java. - __ set(_thread_in_Java, G3_scratch); - __ st(G3_scratch, G2_thread, JavaThread::thread_state_offset()); - __ bind(after_transition); - - Label no_reguard; - __ ld(G2_thread, JavaThread::stack_guard_state_offset(), G3_scratch); - __ cmp_and_br_short(G3_scratch, JavaThread::stack_guard_yellow_reserved_disabled, Assembler::notEqual, Assembler::pt, no_reguard); - - save_native_result(masm, ret_type, stack_slots); - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); - __ delayed()->nop(); - - __ restore_thread(L7_thread_cache); // restore G2_thread - restore_native_result(masm, ret_type, stack_slots); - - __ bind(no_reguard); - - // Handle possible exception (will unlock if necessary) - - // native result if any is live in freg or I0 (and I1 if long and 32bit vm) - - // Unlock - if (method->is_synchronized()) { - Label done; - Register I2_ex_oop = I2; - const Register L3_box = L3; - // Get locked oop from the handle we passed to jni - __ ld_ptr(L6_handle, 0, L4); - __ add(SP, lock_offset+STACK_BIAS, L3_box); - // Must save pending exception around the slow-path VM call. Since it's a - // leaf call, the pending exception (if any) can be kept in a register. - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), I2_ex_oop); - // Now unlock - // (Roop, Rmark, Rbox, Rscratch) - __ compiler_unlock_object(L4, L1, L3_box, L2); - __ br(Assembler::equal, false, Assembler::pt, done); - __ delayed()-> add(SP, lock_offset+STACK_BIAS, L3_box); - - // save and restore any potential method result value around the unlocking - // operation. Will save in I0 (or stack for FP returns). - save_native_result(masm, ret_type, stack_slots); - - // Must clear pending-exception before re-entering the VM. Since this is - // a leaf call, pending-exception-oop can be safely kept in a register. - __ st_ptr(G0, G2_thread, in_bytes(Thread::pending_exception_offset())); - - // slow case of monitor enter. Inline a special case of call_VM that - // disallows any pending_exception. - __ mov(L3_box, O1); - - // Pass in current thread pointer - __ mov(G2_thread, O2); - - __ call(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C), relocInfo::runtime_call_type); - __ delayed()->mov(L4, O0); // Need oop in O0 - - __ restore_thread(L7_thread_cache); // restore G2_thread - -#ifdef ASSERT - { Label L; - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O0); - __ br_null_short(O0, Assembler::pt, L); - __ stop("no pending exception allowed on exit from IR::monitorexit"); - __ bind(L); - } -#endif - restore_native_result(masm, ret_type, stack_slots); - // check_forward_pending_exception jump to forward_exception if any pending - // exception is set. The forward_exception routine expects to see the - // exception in pending_exception and not in a register. Kind of clumsy, - // since all folks who branch to forward_exception must have tested - // pending_exception first and hence have it in a register already. - __ st_ptr(I2_ex_oop, G2_thread, in_bytes(Thread::pending_exception_offset())); - __ bind(done); - } - - // Tell dtrace about this method exit - { - SkipIfEqual skip_if( - masm, G3_scratch, &DTraceMethodProbes, Assembler::zero); - save_native_result(masm, ret_type, stack_slots); - __ set_metadata_constant(method(), O1); - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), - G2_thread, O1); - restore_native_result(masm, ret_type, stack_slots); - } - - // Clear "last Java frame" SP and PC. - __ verify_thread(); // G2_thread must be correct - __ reset_last_Java_frame(); - - // Unbox oop result, e.g. JNIHandles::resolve value in I0. - if (is_reference_type(ret_type)) { - __ resolve_jobject(I0, G3_scratch); - } - - if (CheckJNICalls) { - // clear_pending_jni_exception_check - __ st_ptr(G0, G2_thread, JavaThread::pending_jni_exception_check_fn_offset()); - } - - if (!is_critical_native) { - // reset handle block - __ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), L5); - __ st(G0, L5, JNIHandleBlock::top_offset_in_bytes()); - - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), G3_scratch); - check_forward_pending_exception(masm, G3_scratch); - } - - - // Return - - __ ret(); - __ delayed()->restore(); - - __ flush(); - - nmethod *nm = nmethod::new_native_nmethod(method, - compile_id, - masm->code(), - vep_offset, - frame_complete, - stack_slots / VMRegImpl::slots_per_word, - (is_static ? in_ByteSize(klass_offset) : in_ByteSize(receiver_offset)), - in_ByteSize(lock_offset), - oop_maps); - - if (is_critical_native) { - nm->set_lazy_critical_native(true); - } - return nm; - -} - -// this function returns the adjust size (in number of words) to a c2i adapter -// activation for use during deoptimization -int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) { - assert(callee_locals >= callee_parameters, - "test and remove; got more parms than locals"); - if (callee_locals < callee_parameters) - return 0; // No adjustment for negative locals - int diff = (callee_locals - callee_parameters) * Interpreter::stackElementWords; - return align_up(diff, WordsPerLong); -} - -// "Top of Stack" slots that may be unused by the calling convention but must -// otherwise be preserved. -// On Intel these are not necessary and the value can be zero. -// On Sparc this describes the words reserved for storing a register window -// when an interrupt occurs. -uint SharedRuntime::out_preserve_stack_slots() { - return frame::register_save_words * VMRegImpl::slots_per_word; -} - -static void gen_new_frame(MacroAssembler* masm, bool deopt) { -// -// Common out the new frame generation for deopt and uncommon trap -// - Register G3pcs = G3_scratch; // Array of new pcs (input) - Register Oreturn0 = O0; - Register Oreturn1 = O1; - Register O2UnrollBlock = O2; - Register O3array = O3; // Array of frame sizes (input) - Register O4array_size = O4; // number of frames (input) - Register O7frame_size = O7; // number of frames (input) - - __ ld_ptr(O3array, 0, O7frame_size); - __ sub(G0, O7frame_size, O7frame_size); - __ save(SP, O7frame_size, SP); - __ ld_ptr(G3pcs, 0, I7); // load frame's new pc - - #ifdef ASSERT - // make sure that the frames are aligned properly - #endif - - // Deopt needs to pass some extra live values from frame to frame - - if (deopt) { - __ mov(Oreturn0->after_save(), Oreturn0); - __ mov(Oreturn1->after_save(), Oreturn1); - } - - __ mov(O4array_size->after_save(), O4array_size); - __ sub(O4array_size, 1, O4array_size); - __ mov(O3array->after_save(), O3array); - __ mov(O2UnrollBlock->after_save(), O2UnrollBlock); - __ add(G3pcs, wordSize, G3pcs); // point to next pc value - - #ifdef ASSERT - // trash registers to show a clear pattern in backtraces - __ set(0xDEAD0000, I0); - __ add(I0, 2, I1); - __ add(I0, 4, I2); - __ add(I0, 6, I3); - __ add(I0, 8, I4); - // Don't touch I5 could have valuable savedSP - __ set(0xDEADBEEF, L0); - __ mov(L0, L1); - __ mov(L0, L2); - __ mov(L0, L3); - __ mov(L0, L4); - __ mov(L0, L5); - - // trash the return value as there is nothing to return yet - __ set(0xDEAD0001, O7); - #endif - - __ mov(SP, O5_savedSP); -} - - -static void make_new_frames(MacroAssembler* masm, bool deopt) { - // - // loop through the UnrollBlock info and create new frames - // - Register G3pcs = G3_scratch; - Register Oreturn0 = O0; - Register Oreturn1 = O1; - Register O2UnrollBlock = O2; - Register O3array = O3; - Register O4array_size = O4; - Label loop; - -#ifdef ASSERT - // Compilers generate code that bang the stack by as much as the - // interpreter would need. So this stack banging should never - // trigger a fault. Verify that it does not on non product builds. - if (UseStackBanging) { - // Get total frame size for interpreted frames - __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes(), O4); - __ bang_stack_size(O4, O3, G3_scratch); - } -#endif - - __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::number_of_frames_offset_in_bytes(), O4array_size); - __ ld_ptr(O2UnrollBlock, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes(), G3pcs); - __ ld_ptr(O2UnrollBlock, Deoptimization::UnrollBlock::frame_sizes_offset_in_bytes(), O3array); - - // Adjust old interpreter frame to make space for new frame's extra java locals - // - // We capture the original sp for the transition frame only because it is needed in - // order to properly calculate interpreter_sp_adjustment. Even though in real life - // every interpreter frame captures a savedSP it is only needed at the transition - // (fortunately). If we had to have it correct everywhere then we would need to - // be told the sp_adjustment for each frame we create. If the frame size array - // were to have twice the frame count entries then we could have pairs [sp_adjustment, frame_size] - // for each frame we create and keep up the illusion every where. - // - - __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::caller_adjustment_offset_in_bytes(), O7); - __ mov(SP, O5_savedSP); // remember initial sender's original sp before adjustment - __ sub(SP, O7, SP); - -#ifdef ASSERT - // make sure that there is at least one entry in the array - __ tst(O4array_size); - __ breakpoint_trap(Assembler::zero, Assembler::icc); -#endif - - // Now push the new interpreter frames - __ bind(loop); - - // allocate a new frame, filling the registers - - gen_new_frame(masm, deopt); // allocate an interpreter frame - - __ cmp_zero_and_br(Assembler::notZero, O4array_size, loop); - __ delayed()->add(O3array, wordSize, O3array); - __ ld_ptr(G3pcs, 0, O7); // load final frame new pc - -} - -//------------------------------generate_deopt_blob---------------------------- -// Ought to generate an ideal graph & compile, but here's some SPARC ASM -// instead. -void SharedRuntime::generate_deopt_blob() { - // allocate space for the code - ResourceMark rm; - // setup code generation tools - int pad = VerifyThread ? 512 : 0;// Extra slop space for more verify code -#ifdef ASSERT - if (UseStackBanging) { - pad += (JavaThread::stack_shadow_zone_size() / os::vm_page_size())*16 + 32; - } -#endif -#if INCLUDE_JVMCI - if (EnableJVMCI) { - pad += 1000; // Increase the buffer size when compiling for JVMCI - } -#endif - CodeBuffer buffer("deopt_blob", 2100+pad, 512); - MacroAssembler* masm = new MacroAssembler(&buffer); - FloatRegister Freturn0 = F0; - Register Greturn1 = G1; - Register Oreturn0 = O0; - Register Oreturn1 = O1; - Register O2UnrollBlock = O2; - Register L0deopt_mode = L0; - Register G4deopt_mode = G4_scratch; - int frame_size_words; - Address saved_Freturn0_addr(FP, -sizeof(double) + STACK_BIAS); - Label cont; - - OopMapSet *oop_maps = new OopMapSet(); - - // - // This is the entry point for code which is returning to a de-optimized - // frame. - // The steps taken by this frame are as follows: - // - push a dummy "register_save" and save the return values (O0, O1, F0/F1, G1) - // and all potentially live registers (at a pollpoint many registers can be live). - // - // - call the C routine: Deoptimization::fetch_unroll_info (this function - // returns information about the number and size of interpreter frames - // which are equivalent to the frame which is being deoptimized) - // - deallocate the unpack frame, restoring only results values. Other - // volatile registers will now be captured in the vframeArray as needed. - // - deallocate the deoptimization frame - // - in a loop using the information returned in the previous step - // push new interpreter frames (take care to propagate the return - // values through each new frame pushed) - // - create a dummy "unpack_frame" and save the return values (O0, O1, F0) - // - call the C routine: Deoptimization::unpack_frames (this function - // lays out values on the interpreter frame which was just created) - // - deallocate the dummy unpack_frame - // - ensure that all the return values are correctly set and then do - // a return to the interpreter entry point - // - // Refer to the following methods for more information: - // - Deoptimization::fetch_unroll_info - // - Deoptimization::unpack_frames - - OopMap* map = NULL; - - int start = __ offset(); - - // restore G2, the trampoline destroyed it - __ get_thread(); - - // On entry we have been called by the deoptimized nmethod with a call that - // replaced the original call (or safepoint polling location) so the deoptimizing - // pc is now in O7. Return values are still in the expected places - - map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words); - __ ba(cont); - __ delayed()->mov(Deoptimization::Unpack_deopt, L0deopt_mode); - - -#if INCLUDE_JVMCI - Label after_fetch_unroll_info_call; - int implicit_exception_uncommon_trap_offset = 0; - int uncommon_trap_offset = 0; - - if (EnableJVMCI) { - masm->block_comment("BEGIN implicit_exception_uncommon_trap"); - implicit_exception_uncommon_trap_offset = __ offset() - start; - - __ ld_ptr(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()), O7); - __ st_ptr(G0, Address(G2_thread, in_bytes(JavaThread::jvmci_implicit_exception_pc_offset()))); - __ add(O7, -8, O7); - - uncommon_trap_offset = __ offset() - start; - - // Save everything in sight. - (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); - __ set_last_Java_frame(SP, NULL); - - __ ld(G2_thread, in_bytes(JavaThread::pending_deoptimization_offset()), O1); - __ sub(G0, 1, L1); - __ st(L1, G2_thread, in_bytes(JavaThread::pending_deoptimization_offset())); - - __ mov((int32_t)Deoptimization::Unpack_reexecute, L0deopt_mode); - __ mov(G2_thread, O0); - __ mov(L0deopt_mode, O2); - __ call(CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap)); - __ delayed()->nop(); - oop_maps->add_gc_map( __ offset()-start, map->deep_copy()); - __ get_thread(); - __ add(O7, 8, O7); - __ reset_last_Java_frame(); - - __ ba(after_fetch_unroll_info_call); - __ delayed()->nop(); // Delay slot - masm->block_comment("END implicit_exception_uncommon_trap"); - } // EnableJVMCI -#endif // INCLUDE_JVMCI - - int exception_offset = __ offset() - start; - - // restore G2, the trampoline destroyed it - __ get_thread(); - - // On entry we have been jumped to by the exception handler (or exception_blob - // for server). O0 contains the exception oop and O7 contains the original - // exception pc. So if we push a frame here it will look to the - // stack walking code (fetch_unroll_info) just like a normal call so - // state will be extracted normally. - - // save exception oop in JavaThread and fall through into the - // exception_in_tls case since they are handled in same way except - // for where the pending exception is kept. - __ st_ptr(Oexception, G2_thread, JavaThread::exception_oop_offset()); - - // - // Vanilla deoptimization with an exception pending in exception_oop - // - int exception_in_tls_offset = __ offset() - start; - - // No need to update oop_map as each call to save_live_registers will produce identical oopmap - // Opens a new stack frame - (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); - - // Restore G2_thread - __ get_thread(); - -#ifdef ASSERT - { - // verify that there is really an exception oop in exception_oop - Label has_exception; - __ ld_ptr(G2_thread, JavaThread::exception_oop_offset(), Oexception); - __ br_notnull_short(Oexception, Assembler::pt, has_exception); - __ stop("no exception in thread"); - __ bind(has_exception); - - // verify that there is no pending exception - Label no_pending_exception; - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - __ ld_ptr(exception_addr, Oexception); - __ br_null_short(Oexception, Assembler::pt, no_pending_exception); - __ stop("must not have pending exception here"); - __ bind(no_pending_exception); - } -#endif - - __ ba(cont); - __ delayed()->mov(Deoptimization::Unpack_exception, L0deopt_mode);; - - // - // Reexecute entry, similar to c2 uncommon trap - // - int reexecute_offset = __ offset() - start; -#if INCLUDE_JVMCI && !defined(COMPILER1) - if (EnableJVMCI && UseJVMCICompiler) { - // JVMCI does not use this kind of deoptimization - __ should_not_reach_here(); - } -#endif - // No need to update oop_map as each call to save_live_registers will produce identical oopmap - (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words); - - __ mov(Deoptimization::Unpack_reexecute, L0deopt_mode); - - __ bind(cont); - - __ set_last_Java_frame(SP, noreg); - - // do the call by hand so we can get the oopmap - - __ mov(G2_thread, L7_thread_cache); - __ mov(L0deopt_mode, O1); - __ call(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info), relocInfo::runtime_call_type); - __ delayed()->mov(G2_thread, O0); - - // Set an oopmap for the call site this describes all our saved volatile registers - - oop_maps->add_gc_map( __ offset()-start, map); - - __ mov(L7_thread_cache, G2_thread); - - __ reset_last_Java_frame(); - -#if INCLUDE_JVMCI - if (EnableJVMCI) { - __ bind(after_fetch_unroll_info_call); - } -#endif - // NOTE: we know that only O0/O1 will be reloaded by restore_result_registers - // so this move will survive - - __ mov(L0deopt_mode, G4deopt_mode); - - __ mov(O0, O2UnrollBlock->after_save()); - - RegisterSaver::restore_result_registers(masm); - - __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), G4deopt_mode); - Label noException; - __ cmp_and_br_short(G4deopt_mode, Deoptimization::Unpack_exception, Assembler::notEqual, Assembler::pt, noException); - - // Move the pending exception from exception_oop to Oexception so - // the pending exception will be picked up the interpreter. - __ ld_ptr(G2_thread, in_bytes(JavaThread::exception_oop_offset()), Oexception); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_oop_offset())); - __ st_ptr(G0, G2_thread, in_bytes(JavaThread::exception_pc_offset())); - __ bind(noException); - - // deallocate the deoptimization frame taking care to preserve the return values - __ mov(Oreturn0, Oreturn0->after_save()); - __ mov(Oreturn1, Oreturn1->after_save()); - __ mov(O2UnrollBlock, O2UnrollBlock->after_save()); - __ restore(); - - // Allocate new interpreter frame(s) and possible c2i adapter frame - - make_new_frames(masm, true); - - // push a dummy "unpack_frame" taking care of float return values and - // call Deoptimization::unpack_frames to have the unpacker layout - // information in the interpreter frames just created and then return - // to the interpreter entry point - __ save(SP, -frame_size_words*wordSize, SP); - __ stf(FloatRegisterImpl::D, Freturn0, saved_Freturn0_addr); - // LP64 uses g4 in set_last_Java_frame - __ mov(G4deopt_mode, O1); - __ set_last_Java_frame(SP, G0); - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O1); - __ reset_last_Java_frame(); - __ ldf(FloatRegisterImpl::D, saved_Freturn0_addr, Freturn0); - - __ ret(); - __ delayed()->restore(); - - masm->flush(); - _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words); - _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); -#if INCLUDE_JVMCI - if (EnableJVMCI) { - _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset); - _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); - } -#endif -} - -#ifdef COMPILER2 - -//------------------------------generate_uncommon_trap_blob-------------------- -// Ought to generate an ideal graph & compile, but here's some SPARC ASM -// instead. -void SharedRuntime::generate_uncommon_trap_blob() { - // allocate space for the code - ResourceMark rm; - // setup code generation tools - int pad = VerifyThread ? 512 : 0; -#ifdef ASSERT - if (UseStackBanging) { - pad += (JavaThread::stack_shadow_zone_size() / os::vm_page_size())*16 + 32; - } -#endif - CodeBuffer buffer("uncommon_trap_blob", 2700+pad, 512); - MacroAssembler* masm = new MacroAssembler(&buffer); - Register O2UnrollBlock = O2; - Register O2klass_index = O2; - - // - // This is the entry point for all traps the compiler takes when it thinks - // it cannot handle further execution of compilation code. The frame is - // deoptimized in these cases and converted into interpreter frames for - // execution - // The steps taken by this frame are as follows: - // - push a fake "unpack_frame" - // - call the C routine Deoptimization::uncommon_trap (this function - // packs the current compiled frame into vframe arrays and returns - // information about the number and size of interpreter frames which - // are equivalent to the frame which is being deoptimized) - // - deallocate the "unpack_frame" - // - deallocate the deoptimization frame - // - in a loop using the information returned in the previous step - // push interpreter frames; - // - create a dummy "unpack_frame" - // - call the C routine: Deoptimization::unpack_frames (this function - // lays out values on the interpreter frame which was just created) - // - deallocate the dummy unpack_frame - // - return to the interpreter entry point - // - // Refer to the following methods for more information: - // - Deoptimization::uncommon_trap - // - Deoptimization::unpack_frame - - // the unloaded class index is in O0 (first parameter to this blob) - - // push a dummy "unpack_frame" - // and call Deoptimization::uncommon_trap to pack the compiled frame into - // vframe array and return the UnrollBlock information - __ save_frame(0); - __ set_last_Java_frame(SP, noreg); - __ mov(I0, O2klass_index); - __ mov(Deoptimization::Unpack_uncommon_trap, O3); // exec mode - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::uncommon_trap), G2_thread, O2klass_index, O3); - __ reset_last_Java_frame(); - __ mov(O0, O2UnrollBlock->after_save()); - __ restore(); - - // deallocate the deoptimized frame taking care to preserve the return values - __ mov(O2UnrollBlock, O2UnrollBlock->after_save()); - __ restore(); - -#ifdef ASSERT - { Label L; - __ ld(O2UnrollBlock, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes(), O1); - __ cmp_and_br_short(O1, Deoptimization::Unpack_uncommon_trap, Assembler::equal, Assembler::pt, L); - __ stop("SharedRuntime::generate_deopt_blob: expected Unpack_uncommon_trap"); - __ bind(L); - } -#endif - - // Allocate new interpreter frame(s) and possible c2i adapter frame - - make_new_frames(masm, false); - - // push a dummy "unpack_frame" taking care of float return values and - // call Deoptimization::unpack_frames to have the unpacker layout - // information in the interpreter frames just created and then return - // to the interpreter entry point - __ save_frame(0); - __ set_last_Java_frame(SP, noreg); - __ mov(Deoptimization::Unpack_uncommon_trap, O3); // indicate it is the uncommon trap case - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames), G2_thread, O3); - __ reset_last_Java_frame(); - __ ret(); - __ delayed()->restore(); - - masm->flush(); - _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, NULL, __ total_frame_size_in_bytes(0)/wordSize); -} - -#endif // COMPILER2 - -//------------------------------generate_handler_blob------------------- -// -// Generate a special Compile2Runtime blob that saves all registers, and sets -// up an OopMap. -// -// This blob is jumped to (via a breakpoint and the signal handler) from a -// safepoint in compiled code. On entry to this blob, O7 contains the -// address in the original nmethod at which we should resume normal execution. -// Thus, this blob looks like a subroutine which must preserve lots of -// registers and return normally. Note that O7 is never register-allocated, -// so it is guaranteed to be free here. -// - -// The hardest part of what this blob must do is to save the 64-bit %o -// registers in the 32-bit build. A simple 'save' turn the %o's to %i's and -// an interrupt will chop off their heads. Making space in the caller's frame -// first will let us save the 64-bit %o's before save'ing, but we cannot hand -// the adjusted FP off to the GC stack-crawler: this will modify the caller's -// SP and mess up HIS OopMaps. So we first adjust the caller's SP, then save -// the 64-bit %o's, then do a save, then fixup the caller's SP (our FP). -// Tricky, tricky, tricky... - -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { - assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before"); - - // allocate space for the code - ResourceMark rm; - // setup code generation tools - // Measured 8/7/03 at 896 in 32bit debug build (no VerifyThread) - // Measured 8/7/03 at 1080 in 32bit debug build (VerifyThread) - CodeBuffer buffer("handler_blob", 1600, 512); - MacroAssembler* masm = new MacroAssembler(&buffer); - int frame_size_words; - OopMapSet *oop_maps = new OopMapSet(); - OopMap* map = NULL; - - int start = __ offset(); - - bool cause_return = (poll_type == POLL_AT_RETURN); - // If this causes a return before the processing, then do a "restore" - if (cause_return) { - __ restore(); - } else { - // Make it look like we were called via the poll - // so that frame constructor always sees a valid return address - __ ld_ptr(Address(G2_thread, JavaThread::saved_exception_pc_offset()), O7); - __ sub(O7, frame::pc_return_offset, O7); - } - - map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words); - - // setup last_Java_sp (blows G4) - __ set_last_Java_frame(SP, noreg); - - Register saved_O7 = O7->after_save(); - if (!cause_return) { - // Keep a copy of the return pc in L0 to detect if it gets modified - __ mov(saved_O7, L0); - // Adjust and keep a copy of our npc saved by the signal handler - __ ld_ptr(Address(G2_thread, JavaThread::saved_exception_npc_offset()), L1); - __ sub(L1, frame::pc_return_offset, L1); - } - - // call into the runtime to handle illegal instructions exception - // Do not use call_VM_leaf, because we need to make a GC map at this call site. - __ mov(G2_thread, O0); - __ save_thread(L7_thread_cache); - __ call(call_ptr); - __ delayed()->nop(); - - // Set an oopmap for the call site. - // We need this not only for callee-saved registers, but also for volatile - // registers that the compiler might be keeping live across a safepoint. - - oop_maps->add_gc_map( __ offset() - start, map); - - __ restore_thread(L7_thread_cache); - // clear last_Java_sp - __ reset_last_Java_frame(); - - // Check for exceptions - Label pending; - - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O1); - __ br_notnull_short(O1, Assembler::pn, pending); - - if (!cause_return) { - // If nobody modified our return pc then we must return to the npc which he saved in L1 - __ cmp(saved_O7, L0); - __ movcc(Assembler::equal, false, Assembler::ptr_cc, L1, saved_O7); - } - - RegisterSaver::restore_live_registers(masm); - - // We are back the the original state on entry and ready to go. - - __ retl(); - __ delayed()->nop(); - - // Pending exception after the safepoint - - __ bind(pending); - - RegisterSaver::restore_live_registers(masm); - - // We are back the the original state on entry. - - // Tail-call forward_exception_entry, with the issuing PC in O7, - // so it looks like the original nmethod called forward_exception_entry. - __ set((intptr_t)StubRoutines::forward_exception_entry(), O0); - __ JMP(O0, 0); - __ delayed()->nop(); - - // ------------- - // make sure all code is generated - masm->flush(); - - // return exception blob - return SafepointBlob::create(&buffer, oop_maps, frame_size_words); -} - -// -// generate_resolve_blob - call resolution (static/virtual/opt-virtual/ic-miss -// -// Generate a stub that calls into vm to find out the proper destination -// of a java call. All the argument registers are live at this point -// but since this is generic code we don't know what they are and the caller -// must do any gc of the args. -// -RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { - assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before"); - - // allocate space for the code - ResourceMark rm; - // setup code generation tools - // Measured 8/7/03 at 896 in 32bit debug build (no VerifyThread) - // Measured 8/7/03 at 1080 in 32bit debug build (VerifyThread) - CodeBuffer buffer(name, 1600, 512); - MacroAssembler* masm = new MacroAssembler(&buffer); - int frame_size_words; - OopMapSet *oop_maps = new OopMapSet(); - OopMap* map = NULL; - - int start = __ offset(); - - map = RegisterSaver::save_live_registers(masm, 0, &frame_size_words); - - int frame_complete = __ offset(); - - // setup last_Java_sp (blows G4) - __ set_last_Java_frame(SP, noreg); - - // call into the runtime to handle illegal instructions exception - // Do not use call_VM_leaf, because we need to make a GC map at this call site. - __ mov(G2_thread, O0); - __ save_thread(L7_thread_cache); - __ call(destination, relocInfo::runtime_call_type); - __ delayed()->nop(); - - // O0 contains the address we are going to jump to assuming no exception got installed - - // Set an oopmap for the call site. - // We need this not only for callee-saved registers, but also for volatile - // registers that the compiler might be keeping live across a safepoint. - - oop_maps->add_gc_map( __ offset() - start, map); - - __ restore_thread(L7_thread_cache); - // clear last_Java_sp - __ reset_last_Java_frame(); - - // Check for exceptions - Label pending; - - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), O1); - __ br_notnull_short(O1, Assembler::pn, pending); - - // get the returned Method* - - __ get_vm_result_2(G5_method); - __ stx(G5_method, SP, RegisterSaver::G5_offset()+STACK_BIAS); - - // O0 is where we want to jump, overwrite G3 which is saved and scratch - - __ stx(O0, SP, RegisterSaver::G3_offset()+STACK_BIAS); - - RegisterSaver::restore_live_registers(masm); - - // We are back the the original state on entry and ready to go. - - __ JMP(G3, 0); - __ delayed()->nop(); - - // Pending exception after the safepoint - - __ bind(pending); - - RegisterSaver::restore_live_registers(masm); - - // We are back the the original state on entry. - - // Tail-call forward_exception_entry, with the issuing PC in O7, - // so it looks like the original nmethod called forward_exception_entry. - __ set((intptr_t)StubRoutines::forward_exception_entry(), O0); - __ JMP(O0, 0); - __ delayed()->nop(); - - // ------------- - // make sure all code is generated - masm->flush(); - - // return the blob - // frame_size_words or bytes?? - return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_words, oop_maps, true); -} diff --git a/src/hotspot/cpu/sparc/sparc.ad b/src/hotspot/cpu/sparc/sparc.ad deleted file mode 100644 --- a/src/hotspot/cpu/sparc/sparc.ad +++ /dev/null @@ -1,10950 +0,0 @@ -// -// Copyright (c) 1998, 2020, 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. -// -// - -// SPARC Architecture Description File - -//----------REGISTER DEFINITION BLOCK------------------------------------------ -// This information is used by the matcher and the register allocator to -// describe individual registers and classes of registers within the target -// archtecture. -register %{ -//----------Architecture Description Register Definitions---------------------- -// General Registers -// "reg_def" name ( register save type, C convention save type, -// ideal register type, encoding, vm name ); -// Register Save Types: -// -// NS = No-Save: The register allocator assumes that these registers -// can be used without saving upon entry to the method, & -// that they do not need to be saved at call sites. -// -// SOC = Save-On-Call: The register allocator assumes that these registers -// can be used without saving upon entry to the method, -// but that they must be saved at call sites. -// -// SOE = Save-On-Entry: The register allocator assumes that these registers -// must be saved before using them upon entry to the -// method, but they do not need to be saved at call -// sites. -// -// AS = Always-Save: The register allocator assumes that these registers -// must be saved before using them upon entry to the -// method, & that they must be saved at call sites. -// -// Ideal Register Type is used to determine how to save & restore a -// register. Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get -// spilled with LoadP/StoreP. If the register supports both, use Op_RegI. -// -// The encoding number is the actual bit-pattern placed into the opcodes. - - -// ---------------------------- -// Integer/Long Registers -// ---------------------------- - -// Need to expose the hi/lo aspect of 64-bit registers -// This register set is used for both the 64-bit build and -// the 32-bit build with 1-register longs. - -// Global Registers 0-7 -reg_def R_G0H( NS, NS, Op_RegI,128, G0->as_VMReg()->next()); -reg_def R_G0 ( NS, NS, Op_RegI, 0, G0->as_VMReg()); -reg_def R_G1H(SOC, SOC, Op_RegI,129, G1->as_VMReg()->next()); -reg_def R_G1 (SOC, SOC, Op_RegI, 1, G1->as_VMReg()); -reg_def R_G2H( NS, NS, Op_RegI,130, G2->as_VMReg()->next()); -reg_def R_G2 ( NS, NS, Op_RegI, 2, G2->as_VMReg()); -reg_def R_G3H(SOC, SOC, Op_RegI,131, G3->as_VMReg()->next()); -reg_def R_G3 (SOC, SOC, Op_RegI, 3, G3->as_VMReg()); -reg_def R_G4H(SOC, SOC, Op_RegI,132, G4->as_VMReg()->next()); -reg_def R_G4 (SOC, SOC, Op_RegI, 4, G4->as_VMReg()); -reg_def R_G5H(SOC, SOC, Op_RegI,133, G5->as_VMReg()->next()); -reg_def R_G5 (SOC, SOC, Op_RegI, 5, G5->as_VMReg()); -reg_def R_G6H( NS, NS, Op_RegI,134, G6->as_VMReg()->next()); -reg_def R_G6 ( NS, NS, Op_RegI, 6, G6->as_VMReg()); -reg_def R_G7H( NS, NS, Op_RegI,135, G7->as_VMReg()->next()); -reg_def R_G7 ( NS, NS, Op_RegI, 7, G7->as_VMReg()); - -// Output Registers 0-7 -reg_def R_O0H(SOC, SOC, Op_RegI,136, O0->as_VMReg()->next()); -reg_def R_O0 (SOC, SOC, Op_RegI, 8, O0->as_VMReg()); -reg_def R_O1H(SOC, SOC, Op_RegI,137, O1->as_VMReg()->next()); -reg_def R_O1 (SOC, SOC, Op_RegI, 9, O1->as_VMReg()); -reg_def R_O2H(SOC, SOC, Op_RegI,138, O2->as_VMReg()->next()); -reg_def R_O2 (SOC, SOC, Op_RegI, 10, O2->as_VMReg()); -reg_def R_O3H(SOC, SOC, Op_RegI,139, O3->as_VMReg()->next()); -reg_def R_O3 (SOC, SOC, Op_RegI, 11, O3->as_VMReg()); -reg_def R_O4H(SOC, SOC, Op_RegI,140, O4->as_VMReg()->next()); -reg_def R_O4 (SOC, SOC, Op_RegI, 12, O4->as_VMReg()); -reg_def R_O5H(SOC, SOC, Op_RegI,141, O5->as_VMReg()->next()); -reg_def R_O5 (SOC, SOC, Op_RegI, 13, O5->as_VMReg()); -reg_def R_SPH( NS, NS, Op_RegI,142, SP->as_VMReg()->next()); -reg_def R_SP ( NS, NS, Op_RegI, 14, SP->as_VMReg()); -reg_def R_O7H(SOC, SOC, Op_RegI,143, O7->as_VMReg()->next()); -reg_def R_O7 (SOC, SOC, Op_RegI, 15, O7->as_VMReg()); - -// Local Registers 0-7 -reg_def R_L0H( NS, NS, Op_RegI,144, L0->as_VMReg()->next()); -reg_def R_L0 ( NS, NS, Op_RegI, 16, L0->as_VMReg()); -reg_def R_L1H( NS, NS, Op_RegI,145, L1->as_VMReg()->next()); -reg_def R_L1 ( NS, NS, Op_RegI, 17, L1->as_VMReg()); -reg_def R_L2H( NS, NS, Op_RegI,146, L2->as_VMReg()->next()); -reg_def R_L2 ( NS, NS, Op_RegI, 18, L2->as_VMReg()); -reg_def R_L3H( NS, NS, Op_RegI,147, L3->as_VMReg()->next()); -reg_def R_L3 ( NS, NS, Op_RegI, 19, L3->as_VMReg()); -reg_def R_L4H( NS, NS, Op_RegI,148, L4->as_VMReg()->next()); -reg_def R_L4 ( NS, NS, Op_RegI, 20, L4->as_VMReg()); -reg_def R_L5H( NS, NS, Op_RegI,149, L5->as_VMReg()->next()); -reg_def R_L5 ( NS, NS, Op_RegI, 21, L5->as_VMReg()); -reg_def R_L6H( NS, NS, Op_RegI,150, L6->as_VMReg()->next()); -reg_def R_L6 ( NS, NS, Op_RegI, 22, L6->as_VMReg()); -reg_def R_L7H( NS, NS, Op_RegI,151, L7->as_VMReg()->next()); -reg_def R_L7 ( NS, NS, Op_RegI, 23, L7->as_VMReg()); - -// Input Registers 0-7 -reg_def R_I0H( NS, NS, Op_RegI,152, I0->as_VMReg()->next()); -reg_def R_I0 ( NS, NS, Op_RegI, 24, I0->as_VMReg()); -reg_def R_I1H( NS, NS, Op_RegI,153, I1->as_VMReg()->next()); -reg_def R_I1 ( NS, NS, Op_RegI, 25, I1->as_VMReg()); -reg_def R_I2H( NS, NS, Op_RegI,154, I2->as_VMReg()->next()); -reg_def R_I2 ( NS, NS, Op_RegI, 26, I2->as_VMReg()); -reg_def R_I3H( NS, NS, Op_RegI,155, I3->as_VMReg()->next()); -reg_def R_I3 ( NS, NS, Op_RegI, 27, I3->as_VMReg()); -reg_def R_I4H( NS, NS, Op_RegI,156, I4->as_VMReg()->next()); -reg_def R_I4 ( NS, NS, Op_RegI, 28, I4->as_VMReg()); -reg_def R_I5H( NS, NS, Op_RegI,157, I5->as_VMReg()->next()); -reg_def R_I5 ( NS, NS, Op_RegI, 29, I5->as_VMReg()); -reg_def R_FPH( NS, NS, Op_RegI,158, FP->as_VMReg()->next()); -reg_def R_FP ( NS, NS, Op_RegI, 30, FP->as_VMReg()); -reg_def R_I7H( NS, NS, Op_RegI,159, I7->as_VMReg()->next()); -reg_def R_I7 ( NS, NS, Op_RegI, 31, I7->as_VMReg()); - -// ---------------------------- -// Float/Double Registers -// ---------------------------- - -// Float Registers -reg_def R_F0 ( SOC, SOC, Op_RegF, 0, F0->as_VMReg()); -reg_def R_F1 ( SOC, SOC, Op_RegF, 1, F1->as_VMReg()); -reg_def R_F2 ( SOC, SOC, Op_RegF, 2, F2->as_VMReg()); -reg_def R_F3 ( SOC, SOC, Op_RegF, 3, F3->as_VMReg()); -reg_def R_F4 ( SOC, SOC, Op_RegF, 4, F4->as_VMReg()); -reg_def R_F5 ( SOC, SOC, Op_RegF, 5, F5->as_VMReg()); -reg_def R_F6 ( SOC, SOC, Op_RegF, 6, F6->as_VMReg()); -reg_def R_F7 ( SOC, SOC, Op_RegF, 7, F7->as_VMReg()); -reg_def R_F8 ( SOC, SOC, Op_RegF, 8, F8->as_VMReg()); -reg_def R_F9 ( SOC, SOC, Op_RegF, 9, F9->as_VMReg()); -reg_def R_F10( SOC, SOC, Op_RegF, 10, F10->as_VMReg()); -reg_def R_F11( SOC, SOC, Op_RegF, 11, F11->as_VMReg()); -reg_def R_F12( SOC, SOC, Op_RegF, 12, F12->as_VMReg()); -reg_def R_F13( SOC, SOC, Op_RegF, 13, F13->as_VMReg()); -reg_def R_F14( SOC, SOC, Op_RegF, 14, F14->as_VMReg()); -reg_def R_F15( SOC, SOC, Op_RegF, 15, F15->as_VMReg()); -reg_def R_F16( SOC, SOC, Op_RegF, 16, F16->as_VMReg()); -reg_def R_F17( SOC, SOC, Op_RegF, 17, F17->as_VMReg()); -reg_def R_F18( SOC, SOC, Op_RegF, 18, F18->as_VMReg()); -reg_def R_F19( SOC, SOC, Op_RegF, 19, F19->as_VMReg()); -reg_def R_F20( SOC, SOC, Op_RegF, 20, F20->as_VMReg()); -reg_def R_F21( SOC, SOC, Op_RegF, 21, F21->as_VMReg()); -reg_def R_F22( SOC, SOC, Op_RegF, 22, F22->as_VMReg()); -reg_def R_F23( SOC, SOC, Op_RegF, 23, F23->as_VMReg()); -reg_def R_F24( SOC, SOC, Op_RegF, 24, F24->as_VMReg()); -reg_def R_F25( SOC, SOC, Op_RegF, 25, F25->as_VMReg()); -reg_def R_F26( SOC, SOC, Op_RegF, 26, F26->as_VMReg()); -reg_def R_F27( SOC, SOC, Op_RegF, 27, F27->as_VMReg()); -reg_def R_F28( SOC, SOC, Op_RegF, 28, F28->as_VMReg()); -reg_def R_F29( SOC, SOC, Op_RegF, 29, F29->as_VMReg()); -reg_def R_F30( SOC, SOC, Op_RegF, 30, F30->as_VMReg()); -reg_def R_F31( SOC, SOC, Op_RegF, 31, F31->as_VMReg()); - -// Double Registers -// The rules of ADL require that double registers be defined in pairs. -// Each pair must be two 32-bit values, but not necessarily a pair of -// single float registers. In each pair, ADLC-assigned register numbers -// must be adjacent, with the lower number even. Finally, when the -// CPU stores such a register pair to memory, the word associated with -// the lower ADLC-assigned number must be stored to the lower address. - -// These definitions specify the actual bit encodings of the sparc -// double fp register numbers. FloatRegisterImpl in register_sparc.hpp -// wants 0-63, so we have to convert every time we want to use fp regs -// with the macroassembler, using reg_to_DoubleFloatRegister_object(). -// 255 is a flag meaning "don't go here". -// I believe we can't handle callee-save doubles D32 and up until -// the place in the sparc stack crawler that asserts on the 255 is -// fixed up. -reg_def R_D32 (SOC, SOC, Op_RegD, 1, F32->as_VMReg()); -reg_def R_D32x(SOC, SOC, Op_RegD,255, F32->as_VMReg()->next()); -reg_def R_D34 (SOC, SOC, Op_RegD, 3, F34->as_VMReg()); -reg_def R_D34x(SOC, SOC, Op_RegD,255, F34->as_VMReg()->next()); -reg_def R_D36 (SOC, SOC, Op_RegD, 5, F36->as_VMReg()); -reg_def R_D36x(SOC, SOC, Op_RegD,255, F36->as_VMReg()->next()); -reg_def R_D38 (SOC, SOC, Op_RegD, 7, F38->as_VMReg()); -reg_def R_D38x(SOC, SOC, Op_RegD,255, F38->as_VMReg()->next()); -reg_def R_D40 (SOC, SOC, Op_RegD, 9, F40->as_VMReg()); -reg_def R_D40x(SOC, SOC, Op_RegD,255, F40->as_VMReg()->next()); -reg_def R_D42 (SOC, SOC, Op_RegD, 11, F42->as_VMReg()); -reg_def R_D42x(SOC, SOC, Op_RegD,255, F42->as_VMReg()->next()); -reg_def R_D44 (SOC, SOC, Op_RegD, 13, F44->as_VMReg()); -reg_def R_D44x(SOC, SOC, Op_RegD,255, F44->as_VMReg()->next()); -reg_def R_D46 (SOC, SOC, Op_RegD, 15, F46->as_VMReg()); -reg_def R_D46x(SOC, SOC, Op_RegD,255, F46->as_VMReg()->next()); -reg_def R_D48 (SOC, SOC, Op_RegD, 17, F48->as_VMReg()); -reg_def R_D48x(SOC, SOC, Op_RegD,255, F48->as_VMReg()->next()); -reg_def R_D50 (SOC, SOC, Op_RegD, 19, F50->as_VMReg()); -reg_def R_D50x(SOC, SOC, Op_RegD,255, F50->as_VMReg()->next()); -reg_def R_D52 (SOC, SOC, Op_RegD, 21, F52->as_VMReg()); -reg_def R_D52x(SOC, SOC, Op_RegD,255, F52->as_VMReg()->next()); -reg_def R_D54 (SOC, SOC, Op_RegD, 23, F54->as_VMReg()); -reg_def R_D54x(SOC, SOC, Op_RegD,255, F54->as_VMReg()->next()); -reg_def R_D56 (SOC, SOC, Op_RegD, 25, F56->as_VMReg()); -reg_def R_D56x(SOC, SOC, Op_RegD,255, F56->as_VMReg()->next()); -reg_def R_D58 (SOC, SOC, Op_RegD, 27, F58->as_VMReg()); -reg_def R_D58x(SOC, SOC, Op_RegD,255, F58->as_VMReg()->next()); -reg_def R_D60 (SOC, SOC, Op_RegD, 29, F60->as_VMReg()); -reg_def R_D60x(SOC, SOC, Op_RegD,255, F60->as_VMReg()->next()); -reg_def R_D62 (SOC, SOC, Op_RegD, 31, F62->as_VMReg()); -reg_def R_D62x(SOC, SOC, Op_RegD,255, F62->as_VMReg()->next()); - - -// ---------------------------- -// Special Registers -// Condition Codes Flag Registers -// I tried to break out ICC and XCC but it's not very pretty. -// Every Sparc instruction which defs/kills one also kills the other. -// Hence every compare instruction which defs one kind of flags ends -// up needing a kill of the other. -reg_def CCR (SOC, SOC, Op_RegFlags, 0, VMRegImpl::Bad()); - -reg_def FCC0(SOC, SOC, Op_RegFlags, 0, VMRegImpl::Bad()); -reg_def FCC1(SOC, SOC, Op_RegFlags, 1, VMRegImpl::Bad()); -reg_def FCC2(SOC, SOC, Op_RegFlags, 2, VMRegImpl::Bad()); -reg_def FCC3(SOC, SOC, Op_RegFlags, 3, VMRegImpl::Bad()); - -// ---------------------------- -// Specify the enum values for the registers. These enums are only used by the -// OptoReg "class". We can convert these enum values at will to VMReg when needed -// for visibility to the rest of the vm. The order of this enum influences the -// register allocator so having the freedom to set this order and not be stuck -// with the order that is natural for the rest of the vm is worth it. -alloc_class chunk0( - R_L0,R_L0H, R_L1,R_L1H, R_L2,R_L2H, R_L3,R_L3H, R_L4,R_L4H, R_L5,R_L5H, R_L6,R_L6H, R_L7,R_L7H, - R_G0,R_G0H, R_G1,R_G1H, R_G2,R_G2H, R_G3,R_G3H, R_G4,R_G4H, R_G5,R_G5H, R_G6,R_G6H, R_G7,R_G7H, - R_O7,R_O7H, R_SP,R_SPH, R_O0,R_O0H, R_O1,R_O1H, R_O2,R_O2H, R_O3,R_O3H, R_O4,R_O4H, R_O5,R_O5H, - R_I0,R_I0H, R_I1,R_I1H, R_I2,R_I2H, R_I3,R_I3H, R_I4,R_I4H, R_I5,R_I5H, R_FP,R_FPH, R_I7,R_I7H); - -// Note that a register is not allocatable unless it is also mentioned -// in a widely-used reg_class below. Thus, R_G7 and R_G0 are outside i_reg. - -alloc_class chunk1( - // The first registers listed here are those most likely to be used - // as temporaries. We move F0..F7 away from the front of the list, - // to reduce the likelihood of interferences with parameters and - // return values. Likewise, we avoid using F0/F1 for parameters, - // since they are used for return values. - // This FPU fine-tuning is worth about 1% on the SPEC geomean. - R_F8 ,R_F9 ,R_F10,R_F11,R_F12,R_F13,R_F14,R_F15, - R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23, - R_F24,R_F25,R_F26,R_F27,R_F28,R_F29,R_F30,R_F31, - R_F0 ,R_F1 ,R_F2 ,R_F3 ,R_F4 ,R_F5 ,R_F6 ,R_F7 , // used for arguments and return values - R_D32,R_D32x,R_D34,R_D34x,R_D36,R_D36x,R_D38,R_D38x, - R_D40,R_D40x,R_D42,R_D42x,R_D44,R_D44x,R_D46,R_D46x, - R_D48,R_D48x,R_D50,R_D50x,R_D52,R_D52x,R_D54,R_D54x, - R_D56,R_D56x,R_D58,R_D58x,R_D60,R_D60x,R_D62,R_D62x); - -alloc_class chunk2(CCR, FCC0, FCC1, FCC2, FCC3); - -//----------Architecture Description Register Classes-------------------------- -// Several register classes are automatically defined based upon information in -// this architecture description. -// 1) reg_class inline_cache_reg ( as defined in frame section ) -// 2) reg_class interpreter_method_oop_reg ( as defined in frame section ) -// 3) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) -// - -// G0 is not included in integer class since it has special meaning. -reg_class g0_reg(R_G0); - -// ---------------------------- -// Integer Register Classes -// ---------------------------- -// Exclusions from i_reg: -// R_G0: hardwired zero -// R_G2: reserved by HotSpot to the TLS register (invariant within Java) -// R_G6: reserved by Solaris ABI to tools -// R_G7: reserved by Solaris ABI to libthread -// R_O7: Used as a temp in many encodings -reg_class int_reg(R_G1,R_G3,R_G4,R_G5,R_O0,R_O1,R_O2,R_O3,R_O4,R_O5,R_L0,R_L1,R_L2,R_L3,R_L4,R_L5,R_L6,R_L7,R_I0,R_I1,R_I2,R_I3,R_I4,R_I5); - -// Class for all integer registers, except the G registers. This is used for -// encodings which use G registers as temps. The regular inputs to such -// instructions use a "notemp_" prefix, as a hack to ensure that the allocator -// will not put an input into a temp register. -reg_class notemp_int_reg(R_O0,R_O1,R_O2,R_O3,R_O4,R_O5,R_L0,R_L1,R_L2,R_L3,R_L4,R_L5,R_L6,R_L7,R_I0,R_I1,R_I2,R_I3,R_I4,R_I5); - -reg_class g1_regI(R_G1); -reg_class g3_regI(R_G3); -reg_class g4_regI(R_G4); -reg_class o0_regI(R_O0); -reg_class o7_regI(R_O7); - -// ---------------------------- -// Pointer Register Classes -// ---------------------------- -// 64-bit build means 64-bit pointers means hi/lo pairs -reg_class ptr_reg( R_G1H,R_G1, R_G3H,R_G3, R_G4H,R_G4, R_G5H,R_G5, - R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5, - R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7, - R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5 ); -// Lock encodings use G3 and G4 internally -reg_class lock_ptr_reg( R_G1H,R_G1, R_G5H,R_G5, - R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5, - R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7, - R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5 ); -// Special class for storeP instructions, which can store SP or RPC to TLS. -// It is also used for memory addressing, allowing direct TLS addressing. -reg_class sp_ptr_reg( R_G1H,R_G1, R_G2H,R_G2, R_G3H,R_G3, R_G4H,R_G4, R_G5H,R_G5, - R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5, R_SPH,R_SP, - R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7, - R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5, R_FPH,R_FP ); -// R_L7 is the lowest-priority callee-save (i.e., NS) register -// We use it to save R_G2 across calls out of Java. -reg_class l7_regP(R_L7H,R_L7); - -// Other special pointer regs -reg_class g1_regP(R_G1H,R_G1); -reg_class g2_regP(R_G2H,R_G2); -reg_class g3_regP(R_G3H,R_G3); -reg_class g4_regP(R_G4H,R_G4); -reg_class g5_regP(R_G5H,R_G5); -reg_class i0_regP(R_I0H,R_I0); -reg_class o0_regP(R_O0H,R_O0); -reg_class o1_regP(R_O1H,R_O1); -reg_class o2_regP(R_O2H,R_O2); -reg_class o7_regP(R_O7H,R_O7); - - -// ---------------------------- -// Long Register Classes -// ---------------------------- -// Longs in 1 register. Aligned adjacent hi/lo pairs. -// Note: O7 is never in this class; it is sometimes used as an encoding temp. -reg_class long_reg( R_G1H,R_G1, R_G3H,R_G3, R_G4H,R_G4, R_G5H,R_G5 - ,R_O0H,R_O0, R_O1H,R_O1, R_O2H,R_O2, R_O3H,R_O3, R_O4H,R_O4, R_O5H,R_O5 -// 64-bit, longs in 1 register: use all 64-bit integer registers - ,R_L0H,R_L0, R_L1H,R_L1, R_L2H,R_L2, R_L3H,R_L3, R_L4H,R_L4, R_L5H,R_L5, R_L6H,R_L6, R_L7H,R_L7 - ,R_I0H,R_I0, R_I1H,R_I1, R_I2H,R_I2, R_I3H,R_I3, R_I4H,R_I4, R_I5H,R_I5 - ); - -reg_class g1_regL(R_G1H,R_G1); -reg_class g3_regL(R_G3H,R_G3); -reg_class o2_regL(R_O2H,R_O2); -reg_class o7_regL(R_O7H,R_O7); - -// ---------------------------- -// Special Class for Condition Code Flags Register -reg_class int_flags(CCR); -reg_class float_flags(FCC0,FCC1,FCC2,FCC3); -reg_class float_flag0(FCC0); - - -// ---------------------------- -// Float Point Register Classes -// ---------------------------- -// Skip F30/F31, they are reserved for mem-mem copies -reg_class sflt_reg(R_F0,R_F1,R_F2,R_F3,R_F4,R_F5,R_F6,R_F7,R_F8,R_F9,R_F10,R_F11,R_F12,R_F13,R_F14,R_F15,R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29); - -// Paired floating point registers--they show up in the same order as the floats, -// but they are used with the "Op_RegD" type, and always occur in even/odd pairs. -reg_class dflt_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10,R_F11,R_F12,R_F13,R_F14,R_F15, - R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29, - /* Use extra V9 double registers; this AD file does not support V8 */ - R_D32,R_D32x,R_D34,R_D34x,R_D36,R_D36x,R_D38,R_D38x,R_D40,R_D40x,R_D42,R_D42x,R_D44,R_D44x,R_D46,R_D46x, - R_D48,R_D48x,R_D50,R_D50x,R_D52,R_D52x,R_D54,R_D54x,R_D56,R_D56x,R_D58,R_D58x,R_D60,R_D60x,R_D62,R_D62x - ); - -// Paired floating point registers--they show up in the same order as the floats, -// but they are used with the "Op_RegD" type, and always occur in even/odd pairs. -// This class is usable for mis-aligned loads as happen in I2C adapters. -reg_class dflt_low_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10,R_F11,R_F12,R_F13,R_F14,R_F15, - R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29); -%} - -//----------DEFINITION BLOCK--------------------------------------------------- -// Define name --> value mappings to inform the ADLC of an integer valued name -// Current support includes integer values in the range [0, 0x7FFFFFFF] -// Format: -// int_def ( , ); -// Generated Code in ad_.hpp -// #define () -// // value == -// Generated code in ad_.cpp adlc_verification() -// assert( == , "Expect () to equal "); -// -definitions %{ -// The default cost (of an ALU instruction). - int_def DEFAULT_COST ( 100, 100); - int_def HUGE_COST (1000000, 1000000); - -// Memory refs are twice as expensive as run-of-the-mill. - int_def MEMORY_REF_COST ( 200, DEFAULT_COST * 2); - -// Branches are even more expensive. - int_def BRANCH_COST ( 300, DEFAULT_COST * 3); - int_def CALL_COST ( 300, DEFAULT_COST * 3); -%} - - -//----------SOURCE BLOCK------------------------------------------------------- -// This is a block of C++ code which provides values, functions, and -// definitions necessary in the rest of the architecture description -source_hpp %{ -// Header information of the source block. -// Method declarations/definitions which are used outside -// the ad-scope can conveniently be defined here. -// -// To keep related declarations/definitions/uses close together, -// we switch between source %{ }% and source_hpp %{ }% freely as needed. - -// Must be visible to the DFA in dfa_sparc.cpp -extern bool can_branch_register( Node *bol, Node *cmp ); - -extern bool use_block_zeroing(Node* count); - -// Macros to extract hi & lo halves from a long pair. -// G0 is not part of any long pair, so assert on that. -// Prevents accidentally using G1 instead of G0. -#define LONG_HI_REG(x) (x) -#define LONG_LO_REG(x) (x) - -class CallStubImpl { - - //-------------------------------------------------------------- - //---< Used for optimization in Compile::Shorten_branches >--- - //-------------------------------------------------------------- - - public: - // Size of call trampoline stub. - static uint size_call_trampoline() { - return 0; // no call trampolines on this platform - } - - // number of relocations needed by a call trampoline stub - static uint reloc_call_trampoline() { - return 0; // no call trampolines on this platform - } -}; - -class HandlerImpl { - - public: - - static int emit_exception_handler(CodeBuffer &cbuf); - static int emit_deopt_handler(CodeBuffer& cbuf); - - static uint size_exception_handler() { - return ( NativeJump::instruction_size ); // sethi;jmp;nop - } - - static uint size_deopt_handler() { - return ( 4+ NativeJump::instruction_size ); // save;sethi;jmp;restore - } -}; - -class Node::PD { -public: - enum NodeFlags { - _last_flag = Node::_last_flag - }; -}; - -%} - -source %{ -#define __ _masm. - -// tertiary op of a LoadP or StoreP encoding -#define REGP_OP true - -static FloatRegister reg_to_SingleFloatRegister_object(int register_encoding); -static FloatRegister reg_to_DoubleFloatRegister_object(int register_encoding); -static Register reg_to_register_object(int register_encoding); - -void PhaseOutput::pd_perform_mach_node_analysis() { -} - -int MachNode::pd_alignment_required() const { - return 1; -} - -int MachNode::compute_padding(int current_offset) const { - return 0; -} - -// Used by the DFA in dfa_sparc.cpp. -// Check for being able to use a V9 branch-on-register. Requires a -// compare-vs-zero, equal/not-equal, of a value which was zero- or sign- -// extended. Doesn't work following an integer ADD, for example, because of -// overflow (-1 incremented yields 0 plus a carry in the high-order word). On -// 32-bit V9 systems, interrupts currently blow away the high-order 32 bits and -// replace them with zero, which could become sign-extension in a different OS -// release. There's no obvious reason why an interrupt will ever fill these -// bits with non-zero junk (the registers are reloaded with standard LD -// instructions which either zero-fill or sign-fill). -bool can_branch_register( Node *bol, Node *cmp ) { - if( !BranchOnRegister ) return false; - if( cmp->Opcode() == Op_CmpP ) - return true; // No problems with pointer compares - if( cmp->Opcode() == Op_CmpL ) - return true; // No problems with long compares - - if( !SparcV9RegsHiBitsZero ) return false; - if( bol->as_Bool()->_test._test != BoolTest::ne && - bol->as_Bool()->_test._test != BoolTest::eq ) - return false; - - // Check for comparing against a 'safe' value. Any operation which - // clears out the high word is safe. Thus, loads and certain shifts - // are safe, as are non-negative constants. Any operation which - // preserves zero bits in the high word is safe as long as each of its - // inputs are safe. Thus, phis and bitwise booleans are safe if their - // inputs are safe. At present, the only important case to recognize - // seems to be loads. Constants should fold away, and shifts & - // logicals can use the 'cc' forms. - Node *x = cmp->in(1); - if( x->is_Load() ) return true; - if( x->is_Phi() ) { - for( uint i = 1; i < x->req(); i++ ) - if( !x->in(i)->is_Load() ) - return false; - return true; - } - return false; -} - -bool use_block_zeroing(Node* count) { - // Use BIS for zeroing if count is not constant - // or it is >= BlockZeroingLowLimit. - return UseBlockZeroing && (count->find_intptr_t_con(BlockZeroingLowLimit) >= BlockZeroingLowLimit); -} - -// **************************************************************************** - -// REQUIRED FUNCTIONALITY - -// !!!!! Special hack to get all type of calls to specify the byte offset -// from the start of the call to the point where the return address -// will point. -// The "return address" is the address of the call instruction, plus 8. - -int MachCallStaticJavaNode::ret_addr_offset() { - int offset = NativeCall::instruction_size; // call; delay slot - if (_method_handle_invoke) - offset += 4; // restore SP - return offset; -} - -int MachCallDynamicJavaNode::ret_addr_offset() { - int vtable_index = this->_vtable_index; - if (vtable_index < 0) { - // must be invalid_vtable_index, not nonvirtual_vtable_index - assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value"); - return (NativeMovConstReg::instruction_size + - NativeCall::instruction_size); // sethi; setlo; call; delay slot - } else { - assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); - int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes(); - int v_off = entry_offset + vtableEntry::method_offset_in_bytes(); - int klass_load_size; - if (UseCompressedClassPointers) { - assert(Universe::heap() != NULL, "java heap should be initialized"); - klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord; - } else { - klass_load_size = 1*BytesPerInstWord; - } - if (Assembler::is_simm13(v_off)) { - return klass_load_size + - (2*BytesPerInstWord + // ld_ptr, ld_ptr - NativeCall::instruction_size); // call; delay slot - } else { - return klass_load_size + - (4*BytesPerInstWord + // set_hi, set, ld_ptr, ld_ptr - NativeCall::instruction_size); // call; delay slot - } - } -} - -int MachCallRuntimeNode::ret_addr_offset() { - if (MacroAssembler::is_far_target(entry_point())) { - return NativeFarCall::instruction_size; - } else { - return NativeCall::instruction_size; - } -} - -// Indicate if the safepoint node needs the polling page as an input. -// Since Sparc does not have absolute addressing, it does. -bool SafePointNode::needs_polling_address_input() { - return true; -} - -// emit an interrupt that is caught by the debugger (for debugging compiler) -void emit_break(CodeBuffer &cbuf) { - C2_MacroAssembler _masm(&cbuf); - __ breakpoint_trap(); -} - -#ifndef PRODUCT -void MachBreakpointNode::format( PhaseRegAlloc *, outputStream *st ) const { - st->print("TA"); -} -#endif - -void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - emit_break(cbuf); -} - -uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); -} - -// Traceable jump -void emit_jmpl(CodeBuffer &cbuf, int jump_target) { - C2_MacroAssembler _masm(&cbuf); - Register rdest = reg_to_register_object(jump_target); - __ JMP(rdest, 0); - __ delayed()->nop(); -} - -// Traceable jump and set exception pc -void emit_jmpl_set_exception_pc(CodeBuffer &cbuf, int jump_target) { - C2_MacroAssembler _masm(&cbuf); - Register rdest = reg_to_register_object(jump_target); - __ JMP(rdest, 0); - __ delayed()->add(O7, frame::pc_return_offset, Oissuing_pc ); -} - -void emit_nop(CodeBuffer &cbuf) { - C2_MacroAssembler _masm(&cbuf); - __ nop(); -} - -void emit_illtrap(CodeBuffer &cbuf) { - C2_MacroAssembler _masm(&cbuf); - __ illtrap(0); -} - - -intptr_t get_offset_from_base(const MachNode* n, const TypePtr* atype, int disp32) { - assert(n->rule() != loadUB_rule, ""); - - intptr_t offset = 0; - const TypePtr *adr_type = TYPE_PTR_SENTINAL; // Check for base==RegI, disp==immP - const Node* addr = n->get_base_and_disp(offset, adr_type); - assert(adr_type == (const TypePtr*)-1, "VerifyOops: no support for sparc operands with base==RegI, disp==immP"); - assert(addr != NULL && addr != (Node*)-1, "invalid addr"); - assert(addr->bottom_type()->isa_oopptr() == atype, ""); - atype = atype->add_offset(offset); - assert(disp32 == offset, "wrong disp32"); - return atype->_offset; -} - - -intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int disp32) { - assert(n->rule() != loadUB_rule, ""); - - intptr_t offset = 0; - Node* addr = n->in(2); - assert(addr->bottom_type()->isa_oopptr() == atype, ""); - if (addr->is_Mach() && addr->as_Mach()->ideal_Opcode() == Op_AddP) { - Node* a = addr->in(2/*AddPNode::Address*/); - Node* o = addr->in(3/*AddPNode::Offset*/); - offset = o->is_Con() ? o->bottom_type()->is_intptr_t()->get_con() : Type::OffsetBot; - atype = a->bottom_type()->is_ptr()->add_offset(offset); - assert(atype->isa_oop_ptr(), "still an oop"); - } - offset = atype->is_ptr()->_offset; - if (offset != Type::OffsetBot) offset += disp32; - return offset; -} - -static inline jlong replicate_immI(int con, int count, int width) { - // Load a constant replicated "count" times with width "width" - assert(count*width == 8 && width <= 4, "sanity"); - int bit_width = width * 8; - jlong val = con; - val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits - for (int i = 0; i < count - 1; i++) { - val |= (val << bit_width); - } - return val; -} - -static inline jlong replicate_immF(float con) { - // Replicate float con 2 times and pack into vector. - int val = *((int*)&con); - jlong lval = val; - lval = (lval << 32) | (lval & 0xFFFFFFFFl); - return lval; -} - -// Standard Sparc opcode form2 field breakdown -static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22, int f20, int f19, int f0 ) { - f0 &= (1<<19)-1; // Mask displacement to 19 bits - int op = (f30 << 30) | - (f29 << 29) | - (f25 << 25) | - (f22 << 22) | - (f20 << 20) | - (f19 << 19) | - (f0 << 0); - cbuf.insts()->emit_int32(op); -} - -// Standard Sparc opcode form2 field breakdown -static inline void emit2_22(CodeBuffer &cbuf, int f30, int f25, int f22, int f0 ) { - f0 >>= 10; // Drop 10 bits - f0 &= (1<<22)-1; // Mask displacement to 22 bits - int op = (f30 << 30) | - (f25 << 25) | - (f22 << 22) | - (f0 << 0); - cbuf.insts()->emit_int32(op); -} - -// Standard Sparc opcode form3 field breakdown -static inline void emit3(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int f5, int f0 ) { - int op = (f30 << 30) | - (f25 << 25) | - (f19 << 19) | - (f14 << 14) | - (f5 << 5) | - (f0 << 0); - cbuf.insts()->emit_int32(op); -} - -// Standard Sparc opcode form3 field breakdown -static inline void emit3_simm13(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int simm13 ) { - simm13 &= (1<<13)-1; // Mask to 13 bits - int op = (f30 << 30) | - (f25 << 25) | - (f19 << 19) | - (f14 << 14) | - (1 << 13) | // bit to indicate immediate-mode - (simm13<<0); - cbuf.insts()->emit_int32(op); -} - -static inline void emit3_simm10(CodeBuffer &cbuf, int f30, int f25, int f19, int f14, int simm10 ) { - simm10 &= (1<<10)-1; // Mask to 10 bits - emit3_simm13(cbuf,f30,f25,f19,f14,simm10); -} - -#ifdef ASSERT -// Helper function for VerifyOops in emit_form3_mem_reg -void verify_oops_warning(const MachNode *n, int ideal_op, int mem_op) { - warning("VerifyOops encountered unexpected instruction:"); - n->dump(2); - warning("Instruction has ideal_Opcode==Op_%s and op_ld==Op_%s \n", NodeClassNames[ideal_op], NodeClassNames[mem_op]); -} -#endif - - -void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, int primary, int tertiary, - int src1_enc, int disp32, int src2_enc, int dst_enc) { - -#ifdef ASSERT - // The following code implements the +VerifyOops feature. - // It verifies oop values which are loaded into or stored out of - // the current method activation. +VerifyOops complements techniques - // like ScavengeALot, because it eagerly inspects oops in transit, - // as they enter or leave the stack, as opposed to ScavengeALot, - // which inspects oops "at rest", in the stack or heap, at safepoints. - // For this reason, +VerifyOops can sometimes detect bugs very close - // to their point of creation. It can also serve as a cross-check - // on the validity of oop maps, when used toegether with ScavengeALot. - - // It would be good to verify oops at other points, especially - // when an oop is used as a base pointer for a load or store. - // This is presently difficult, because it is hard to know when - // a base address is biased or not. (If we had such information, - // it would be easy and useful to make a two-argument version of - // verify_oop which unbiases the base, and performs verification.) - - assert((uint)tertiary == 0xFFFFFFFF || tertiary == REGP_OP, "valid tertiary"); - bool is_verified_oop_base = false; - bool is_verified_oop_load = false; - bool is_verified_oop_store = false; - int tmp_enc = -1; - if (VerifyOops && src1_enc != R_SP_enc) { - // classify the op, mainly for an assert check - int st_op = 0, ld_op = 0; - switch (primary) { - case Assembler::stb_op3: st_op = Op_StoreB; break; - case Assembler::sth_op3: st_op = Op_StoreC; break; - case Assembler::stx_op3: // may become StoreP or stay StoreI or StoreD0 - case Assembler::stw_op3: st_op = Op_StoreI; break; - case Assembler::std_op3: st_op = Op_StoreL; break; - case Assembler::stf_op3: st_op = Op_StoreF; break; - case Assembler::stdf_op3: st_op = Op_StoreD; break; - - case Assembler::ldsb_op3: ld_op = Op_LoadB; break; - case Assembler::ldub_op3: ld_op = Op_LoadUB; break; - case Assembler::lduh_op3: ld_op = Op_LoadUS; break; - case Assembler::ldsh_op3: ld_op = Op_LoadS; break; - case Assembler::ldx_op3: // may become LoadP or stay LoadI - case Assembler::ldsw_op3: // may become LoadP or stay LoadI - case Assembler::lduw_op3: ld_op = Op_LoadI; break; - case Assembler::ldd_op3: ld_op = Op_LoadL; break; - case Assembler::ldf_op3: ld_op = Op_LoadF; break; - case Assembler::lddf_op3: ld_op = Op_LoadD; break; - case Assembler::prefetch_op3: ld_op = Op_LoadI; break; - - default: ShouldNotReachHere(); - } - if (tertiary == REGP_OP) { - if (st_op == Op_StoreI) st_op = Op_StoreP; - else if (ld_op == Op_LoadI) ld_op = Op_LoadP; - else ShouldNotReachHere(); - if (st_op) { - // a store - // inputs are (0:control, 1:memory, 2:address, 3:value) - Node* n2 = n->in(3); - if (n2 != NULL) { - const Type* t = n2->bottom_type(); - is_verified_oop_store = t->isa_oop_ptr() ? (t->is_ptr()->_offset==0) : false; - } - } else { - // a load - const Type* t = n->bottom_type(); - is_verified_oop_load = t->isa_oop_ptr() ? (t->is_ptr()->_offset==0) : false; - } - } - - if (ld_op) { - // a Load - // inputs are (0:control, 1:memory, 2:address) - if (!(n->ideal_Opcode()==ld_op) && // Following are special cases - !(n->ideal_Opcode()==Op_LoadPLocked && ld_op==Op_LoadP) && - !(n->ideal_Opcode()==Op_LoadI && ld_op==Op_LoadF) && - !(n->ideal_Opcode()==Op_LoadF && ld_op==Op_LoadI) && - !(n->ideal_Opcode()==Op_LoadRange && ld_op==Op_LoadI) && - !(n->ideal_Opcode()==Op_LoadKlass && ld_op==Op_LoadP) && - !(n->ideal_Opcode()==Op_LoadL && ld_op==Op_LoadI) && - !(n->ideal_Opcode()==Op_LoadL_unaligned && ld_op==Op_LoadI) && - !(n->ideal_Opcode()==Op_LoadD_unaligned && ld_op==Op_LoadF) && - !(n->ideal_Opcode()==Op_ConvI2F && ld_op==Op_LoadF) && - !(n->ideal_Opcode()==Op_ConvI2D && ld_op==Op_LoadF) && - !(n->ideal_Opcode()==Op_PrefetchAllocation && ld_op==Op_LoadI) && - !(n->ideal_Opcode()==Op_LoadVector && ld_op==Op_LoadD) && - !(n->rule() == loadUB_rule)) { - verify_oops_warning(n, n->ideal_Opcode(), ld_op); - } - } else if (st_op) { - // a Store - // inputs are (0:control, 1:memory, 2:address, 3:value) - if (!(n->ideal_Opcode()==st_op) && // Following are special cases - !(n->ideal_Opcode()==Op_StoreCM && st_op==Op_StoreB) && - !(n->ideal_Opcode()==Op_StoreI && st_op==Op_StoreF) && - !(n->ideal_Opcode()==Op_StoreF && st_op==Op_StoreI) && - !(n->ideal_Opcode()==Op_StoreL && st_op==Op_StoreI) && - !(n->ideal_Opcode()==Op_StoreVector && st_op==Op_StoreD) && - !(n->ideal_Opcode()==Op_StoreD && st_op==Op_StoreI && n->rule() == storeD0_rule)) { - verify_oops_warning(n, n->ideal_Opcode(), st_op); - } - } - - if (src2_enc == R_G0_enc && n->rule() != loadUB_rule && n->ideal_Opcode() != Op_StoreCM ) { - Node* addr = n->in(2); - if (!(addr->is_Mach() && addr->as_Mach()->ideal_Opcode() == Op_AddP)) { - const TypeOopPtr* atype = addr->bottom_type()->isa_instptr(); // %%% oopptr? - if (atype != NULL) { - intptr_t offset = get_offset_from_base(n, atype, disp32); - intptr_t offset_2 = get_offset_from_base_2(n, atype, disp32); - if (offset != offset_2) { - get_offset_from_base(n, atype, disp32); - get_offset_from_base_2(n, atype, disp32); - } - assert(offset == offset_2, "different offsets"); - if (offset == disp32) { - // we now know that src1 is a true oop pointer - is_verified_oop_base = true; - if (ld_op && src1_enc == dst_enc && ld_op != Op_LoadF && ld_op != Op_LoadD) { - if( primary == Assembler::ldd_op3 ) { - is_verified_oop_base = false; // Cannot 'ldd' into O7 - } else { - tmp_enc = dst_enc; - dst_enc = R_O7_enc; // Load into O7; preserve source oop - assert(src1_enc != dst_enc, ""); - } - } - } - if (st_op && (( offset == oopDesc::klass_offset_in_bytes()) - || offset == oopDesc::mark_offset_in_bytes())) { - // loading the mark should not be allowed either, but - // we don't check this since it conflicts with InlineObjectHash - // usage of LoadINode to get the mark. We could keep the - // check if we create a new LoadMarkNode - // but do not verify the object before its header is initialized - ShouldNotReachHere(); - } - } - } - } - } -#endif - - uint instr = (Assembler::ldst_op << 30) - | (dst_enc << 25) - | (primary << 19) - | (src1_enc << 14); - - uint index = src2_enc; - int disp = disp32; - - if (src1_enc == R_SP_enc || src1_enc == R_FP_enc) { - disp += STACK_BIAS; - // Check that stack offset fits, load into O7 if not - if (!Assembler::is_simm13(disp)) { - C2_MacroAssembler _masm(&cbuf); - __ set(disp, O7); - if (index != R_G0_enc) { - __ add(O7, reg_to_register_object(index), O7); - } - index = R_O7_enc; - disp = 0; - } - } - - if( disp == 0 ) { - // use reg-reg form - // bit 13 is already zero - instr |= index; - } else { - // use reg-imm form - instr |= 0x00002000; // set bit 13 to one - instr |= disp & 0x1FFF; - } - - cbuf.insts()->emit_int32(instr); - -#ifdef ASSERT - if (VerifyOops) { - C2_MacroAssembler _masm(&cbuf); - if (is_verified_oop_base) { - __ verify_oop(reg_to_register_object(src1_enc)); - } - if (is_verified_oop_store) { - __ verify_oop(reg_to_register_object(dst_enc)); - } - if (tmp_enc != -1) { - __ mov(O7, reg_to_register_object(tmp_enc)); - } - if (is_verified_oop_load) { - __ verify_oop(reg_to_register_object(dst_enc)); - } - } -#endif -} - -void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, RelocationHolder const& rspec, bool preserve_g2 = false) { - // The method which records debug information at every safepoint - // expects the call to be the first instruction in the snippet as - // it creates a PcDesc structure which tracks the offset of a call - // from the start of the codeBlob. This offset is computed as - // code_end() - code_begin() of the code which has been emitted - // so far. - // In this particular case we have skirted around the problem by - // putting the "mov" instruction in the delay slot but the problem - // may bite us again at some other point and a cleaner/generic - // solution using relocations would be needed. - C2_MacroAssembler _masm(&cbuf); - __ set_inst_mark(); - - // We flush the current window just so that there is a valid stack copy - // the fact that the current window becomes active again instantly is - // not a problem there is nothing live in it. - -#ifdef ASSERT - int startpos = __ offset(); -#endif /* ASSERT */ - - __ call((address)entry_point, rspec); - - if (preserve_g2) __ delayed()->mov(G2, L7); - else __ delayed()->nop(); - - if (preserve_g2) __ mov(L7, G2); - -#ifdef ASSERT - if (preserve_g2 && (VerifyCompiledCode || VerifyOops)) { - // Trash argument dump slots. - __ set(0xb0b8ac0db0b8ac0d, G1); - __ mov(G1, G5); - __ stx(G1, SP, STACK_BIAS + 0x80); - __ stx(G1, SP, STACK_BIAS + 0x88); - __ stx(G1, SP, STACK_BIAS + 0x90); - __ stx(G1, SP, STACK_BIAS + 0x98); - __ stx(G1, SP, STACK_BIAS + 0xA0); - __ stx(G1, SP, STACK_BIAS + 0xA8); - } -#endif /*ASSERT*/ -} - -//============================================================================= -// REQUIRED FUNCTIONALITY for encoding -void emit_lo(CodeBuffer &cbuf, int val) { } -void emit_hi(CodeBuffer &cbuf, int val) { } - - -//============================================================================= -const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask(); - -int ConstantTable::calculate_table_base_offset() const { - if (UseRDPCForConstantTableBase) { - // The table base offset might be less but then it fits into - // simm13 anyway and we are good (cf. MachConstantBaseNode::emit). - return Assembler::min_simm13(); - } else { - int offset = -(size() / 2); - if (!Assembler::is_simm13(offset)) { - offset = Assembler::min_simm13(); - } - return offset; - } -} - -bool MachConstantBaseNode::requires_postalloc_expand() const { return false; } -void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, PhaseRegAlloc *ra_) { - ShouldNotReachHere(); -} - -void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { - Compile* C = ra_->C; - ConstantTable& constant_table = C->output()->constant_table(); - C2_MacroAssembler _masm(&cbuf); - - Register r = as_Register(ra_->get_encode(this)); - CodeSection* consts_section = __ code()->consts(); - int consts_size = consts_section->align_at_start(consts_section->size()); - assert(constant_table.size() == consts_size, "must be: %d == %d", constant_table.size(), consts_size); - - if (UseRDPCForConstantTableBase) { - // For the following RDPC logic to work correctly the consts - // section must be allocated right before the insts section. This - // assert checks for that. The layout and the SECT_* constants - // are defined in src/share/vm/asm/codeBuffer.hpp. - assert(CodeBuffer::SECT_CONSTS + 1 == CodeBuffer::SECT_INSTS, "must be"); - int insts_offset = __ offset(); - - // Layout: - // - // |----------- consts section ------------|----------- insts section -----------... - // |------ constant table -----|- padding -|------------------x---- - // \ current PC (RDPC instruction) - // |<------------- consts_size ----------->|<- insts_offset ->| - // \ table base - // The table base offset is later added to the load displacement - // so it has to be negative. - int table_base_offset = -(consts_size + insts_offset); - int disp; - - // If the displacement from the current PC to the constant table - // base fits into simm13 we set the constant table base to the - // current PC. - if (Assembler::is_simm13(table_base_offset)) { - constant_table.set_table_base_offset(table_base_offset); - disp = 0; - } else { - // Otherwise we set the constant table base offset to the - // maximum negative displacement of load instructions to keep - // the disp as small as possible: - // - // |<------------- consts_size ----------->|<- insts_offset ->| - // |<--------- min_simm13 --------->|<-------- disp --------->| - // \ table base - table_base_offset = Assembler::min_simm13(); - constant_table.set_table_base_offset(table_base_offset); - disp = (consts_size + insts_offset) + table_base_offset; - } - - __ rdpc(r); - - if (disp == 0) { - // Emitting an additional 'nop' instruction in order not to cause a code - // size adjustment in the code following the table setup (if the instruction - // immediately following after this section is a CTI). - __ nop(); - } - else { - assert(r != O7, "need temporary"); - __ sub(r, __ ensure_simm13_or_reg(disp, O7), r); - } - } - else { - // Materialize the constant table base. - address baseaddr = consts_section->start() + -(constant_table.table_base_offset()); - RelocationHolder rspec = internal_word_Relocation::spec(baseaddr); - AddressLiteral base(baseaddr, rspec); - __ set(base, r); - } -} - -uint MachConstantBaseNode::size(PhaseRegAlloc*) const { - if (UseRDPCForConstantTableBase) { - // This is really the worst case but generally it's only 1 instruction. - return (1 /*rdpc*/ + 1 /*sub*/ + MacroAssembler::worst_case_insts_for_set()) * BytesPerInstWord; - } else { - return MacroAssembler::worst_case_insts_for_set() * BytesPerInstWord; - } -} - -#ifndef PRODUCT -void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { - char reg[128]; - ra_->dump_register(this, reg); - if (UseRDPCForConstantTableBase) { - st->print("RDPC %s\t! constant table base", reg); - } else { - st->print("SET &constanttable,%s\t! constant table base", reg); - } -} -#endif - - -//============================================================================= - -#ifndef PRODUCT -void MachPrologNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { - Compile* C = ra_->C; - - for (int i = 0; i < OptoPrologueNops; i++) { - st->print_cr("NOP"); st->print("\t"); - } - - if( VerifyThread ) { - st->print_cr("Verify_Thread"); st->print("\t"); - } - - size_t framesize = C->output()->frame_size_in_bytes(); - int bangsize = C->output()->bang_size_in_bytes(); - - // Calls to C2R adapters often do not accept exceptional returns. - // We require that their callers must bang for them. But be careful, because - // some VM calls (such as call site linkage) can use several kilobytes of - // stack. But the stack safety zone should account for that. - // See bugs 4446381, 4468289, 4497237. - if (C->output()->need_stack_bang(bangsize)) { - st->print_cr("! stack bang (%d bytes)", bangsize); st->print("\t"); - } - - if (Assembler::is_simm13(-framesize)) { - st->print ("SAVE R_SP,-" SIZE_FORMAT ",R_SP",framesize); - } else { - st->print_cr("SETHI R_SP,hi%%(-" SIZE_FORMAT "),R_G3",framesize); st->print("\t"); - st->print_cr("ADD R_G3,lo%%(-" SIZE_FORMAT "),R_G3",framesize); st->print("\t"); - st->print ("SAVE R_SP,R_G3,R_SP"); - } - -} -#endif - -void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - Compile* C = ra_->C; - C2_MacroAssembler _masm(&cbuf); - - for (int i = 0; i < OptoPrologueNops; i++) { - __ nop(); - } - - __ verify_thread(); - - size_t framesize = C->output()->frame_size_in_bytes(); - assert(framesize >= 16*wordSize, "must have room for reg. save area"); - assert(framesize%(2*wordSize) == 0, "must preserve 2*wordSize alignment"); - int bangsize = C->output()->bang_size_in_bytes(); - - // Calls to C2R adapters often do not accept exceptional returns. - // We require that their callers must bang for them. But be careful, because - // some VM calls (such as call site linkage) can use several kilobytes of - // stack. But the stack safety zone should account for that. - // See bugs 4446381, 4468289, 4497237. - if (C->output()->need_stack_bang(bangsize)) { - __ generate_stack_overflow_check(bangsize); - } - - if (Assembler::is_simm13(-framesize)) { - __ save(SP, -framesize, SP); - } else { - __ sethi(-framesize & ~0x3ff, G3); - __ add(G3, -framesize & 0x3ff, G3); - __ save(SP, G3, SP); - } - C->output()->set_frame_complete( __ offset() ); - - if (!UseRDPCForConstantTableBase && C->has_mach_constant_base_node()) { - // NOTE: We set the table base offset here because users might be - // emitted before MachConstantBaseNode. - ConstantTable& constant_table = C->output()->constant_table(); - constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); - } -} - -uint MachPrologNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); -} - -int MachPrologNode::reloc() const { - return 10; // a large enough number -} - -//============================================================================= -#ifndef PRODUCT -void MachEpilogNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { - Compile* C = ra_->C; - - if(do_polling() && ra_->C->is_method_compilation()) { - st->print("LDX [R_G2 + #poll_offset],L0\t! Load local polling address\n\t"); - st->print("LDX [L0],G0\t!Poll for Safepointing\n\t"); - } - - if(do_polling()) { - if (UseCBCond && !ra_->C->is_method_compilation()) { - st->print("NOP\n\t"); - } - st->print("RET\n\t"); - } - - st->print("RESTORE"); -} -#endif - -void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - C2_MacroAssembler _masm(&cbuf); - Compile* C = ra_->C; - - __ verify_thread(); - - if (StackReservedPages > 0 && C->has_reserved_stack_access()) { - __ reserved_stack_check(); - } - - // If this does safepoint polling, then do it here - if(do_polling() && ra_->C->is_method_compilation()) { - __ ld_ptr(Address(G2_thread, Thread::polling_page_offset()), L0); - __ relocate(relocInfo::poll_return_type); - __ ld_ptr(L0, 0, G0); - } - - // If this is a return, then stuff the restore in the delay slot - if(do_polling()) { - if (UseCBCond && !ra_->C->is_method_compilation()) { - // Insert extra padding for the case when the epilogue is preceded by - // a cbcond jump, which can't be followed by a CTI instruction - __ nop(); - } - __ ret(); - __ delayed()->restore(); - } else { - __ restore(); - } -} - -uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); -} - -int MachEpilogNode::reloc() const { - return 16; // a large enough number -} - -const Pipeline * MachEpilogNode::pipeline() const { - return MachNode::pipeline_class(); -} - -//============================================================================= - -// Figure out which register class each belongs in: rc_int, rc_float, rc_stack -enum RC { rc_bad, rc_int, rc_float, rc_stack }; -static enum RC rc_class( OptoReg::Name reg ) { - if (!OptoReg::is_valid(reg)) return rc_bad; - if (OptoReg::is_stack(reg)) return rc_stack; - VMReg r = OptoReg::as_VMReg(reg); - if (r->is_Register()) return rc_int; - assert(r->is_FloatRegister(), "must be"); - return rc_float; -} - -#ifndef PRODUCT -ATTRIBUTE_PRINTF(2, 3) -static void print_helper(outputStream* st, const char* format, ...) { - const int tab_size = 8; - if (st->position() > tab_size) { - st->cr(); - st->sp(); - } - va_list ap; - va_start(ap, format); - st->vprint(format, ap); - va_end(ap); -} -#endif // !PRODUCT - -static void impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool is_load, int offset, int reg, int opcode, const char *op_str, outputStream* st) { - if (cbuf) { - emit_form3_mem_reg(*cbuf, ra, mach, opcode, -1, R_SP_enc, offset, 0, Matcher::_regEncode[reg]); - } -#ifndef PRODUCT - else { - if (is_load) { - print_helper(st, "%s [R_SP + #%d],R_%s\t! spill", op_str, offset, OptoReg::regname(reg)); - } else { - print_helper(st, "%s R_%s,[R_SP + #%d]\t! spill", op_str, OptoReg::regname(reg), offset); - } - } -#endif -} - -static void impl_mov_helper(CodeBuffer *cbuf, int src, int dst, int op1, int op2, const char *op_str, outputStream* st) { - if (cbuf) { - emit3(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src]); - } -#ifndef PRODUCT - else { - print_helper(st, "%s R_%s,R_%s\t! spill", op_str, OptoReg::regname(src), OptoReg::regname(dst)); - } -#endif -} - -static void mach_spill_copy_implementation_helper(const MachNode* mach, - CodeBuffer *cbuf, - PhaseRegAlloc *ra_, - outputStream* st) { - // Get registers to move - OptoReg::Name src_second = ra_->get_reg_second(mach->in(1)); - OptoReg::Name src_first = ra_->get_reg_first(mach->in(1)); - OptoReg::Name dst_second = ra_->get_reg_second(mach); - OptoReg::Name dst_first = ra_->get_reg_first(mach); - - enum RC src_second_rc = rc_class(src_second); - enum RC src_first_rc = rc_class(src_first); - enum RC dst_second_rc = rc_class(dst_second); - enum RC dst_first_rc = rc_class(dst_first); - - assert(OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register"); - - if (src_first == dst_first && src_second == dst_second) { - return; // Self copy, no move - } - - // -------------------------------------- - // Check for mem-mem move. Load into unused float registers and fall into - // the float-store case. - if (src_first_rc == rc_stack && dst_first_rc == rc_stack) { - int offset = ra_->reg2offset(src_first); - // Further check for aligned-adjacent pair, so we can use a double load - if ((src_first&1) == 0 && src_first+1 == src_second) { - src_second = OptoReg::Name(R_F31_num); - src_second_rc = rc_float; - impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::lddf_op3, "LDDF", st); - } else { - impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::ldf_op3, "LDF ", st); - } - src_first = OptoReg::Name(R_F30_num); - src_first_rc = rc_float; - } - - if( src_second_rc == rc_stack && dst_second_rc == rc_stack ) { - int offset = ra_->reg2offset(src_second); - impl_helper(mach, cbuf, ra_, true, offset, R_F31_num, Assembler::ldf_op3, "LDF ", st); - src_second = OptoReg::Name(R_F31_num); - src_second_rc = rc_float; - } - - // -------------------------------------- - // Check for float->int copy; requires a trip through memory - if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) { - int offset = frame::register_save_words*wordSize; - if (cbuf) { - emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16); - impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); - impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); - emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16); - } -#ifndef PRODUCT - else { - print_helper(st, "SUB R_SP,16,R_SP"); - impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); - impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); - print_helper(st, "ADD R_SP,16,R_SP"); - } -#endif - } - - // Check for float->int copy on T4 - if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) { - // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mdtox_opf, "MOVDTOX", st); - return; - } - impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mstouw_opf, "MOVSTOUW", st); - } - // Check for int->float copy on T4 - if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) { - // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mxtod_opf, "MOVXTOD", st); - return; - } - impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mwtos_opf, "MOVWTOS", st); - } - - // -------------------------------------- - // In the 32-bit 1-reg-longs build ONLY, I see mis-aligned long destinations. - // In such cases, I have to do the big-endian swap. For aligned targets, the - // hardware does the flop for me. Doubles are always aligned, so no problem - // there. Misaligned sources only come from native-long-returns (handled - // special below). - - // -------------------------------------- - // Check for integer reg-reg copy - if (src_first_rc == rc_int && dst_first_rc == rc_int) { - // Else normal reg-reg copy - assert(src_second != dst_first, "smashed second before evacuating it"); - impl_mov_helper(cbuf, src_first, dst_first, Assembler::or_op3, 0, "MOV ", st); - assert((src_first & 1) == 0 && (dst_first & 1) == 0, "never move second-halves of int registers"); - // This moves an aligned adjacent pair. - // See if we are done. - if (src_first + 1 == src_second && dst_first + 1 == dst_second) { - return; - } - } - - // Check for integer store - if (src_first_rc == rc_int && dst_first_rc == rc_stack) { - int offset = ra_->reg2offset(dst_first); - // Further check for aligned-adjacent pair, so we can use a double store - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stx_op3, "STX ", st); - return; - } - impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stw_op3, "STW ", st); - } - - // Check for integer load - if (dst_first_rc == rc_int && src_first_rc == rc_stack) { - int offset = ra_->reg2offset(src_first); - // Further check for aligned-adjacent pair, so we can use a double load - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldx_op3, "LDX ", st); - return; - } - impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); - } - - // Check for float reg-reg copy - if (src_first_rc == rc_float && dst_first_rc == rc_float) { - // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovd_opf, "FMOVD", st); - return; - } - impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovs_opf, "FMOVS", st); - } - - // Check for float store - if (src_first_rc == rc_float && dst_first_rc == rc_stack) { - int offset = ra_->reg2offset(dst_first); - // Further check for aligned-adjacent pair, so we can use a double store - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stdf_op3, "STDF", st); - return; - } - impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); - } - - // Check for float load - if (dst_first_rc == rc_float && src_first_rc == rc_stack) { - int offset = ra_->reg2offset(src_first); - // Further check for aligned-adjacent pair, so we can use a double load - if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { - impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lddf_op3, "LDDF", st); - return; - } - impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldf_op3, "LDF ", st); - } - - // -------------------------------------------------------------------- - // Check for hi bits still needing moving. Only happens for misaligned - // arguments to native calls. - if (src_second == dst_second) { - return; // Self copy; no move - } - assert(src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad"); - - Unimplemented(); -} - -uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, - PhaseRegAlloc *ra_, - bool do_size, - outputStream* st) const { - assert(!do_size, "not supported"); - mach_spill_copy_implementation_helper(this, cbuf, ra_, st); - return 0; -} - -#ifndef PRODUCT -void MachSpillCopyNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { - implementation( NULL, ra_, false, st ); -} -#endif - -void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - implementation( &cbuf, ra_, false, NULL ); -} - -uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); -} - -//============================================================================= -#ifndef PRODUCT -void MachNopNode::format(PhaseRegAlloc *, outputStream *st) const { - st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count); -} -#endif - -void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *) const { - C2_MacroAssembler _masm(&cbuf); - for (int i = 0; i < _count; i += 1) { - __ nop(); - } -} - -uint MachNopNode::size(PhaseRegAlloc *ra_) const { - return 4 * _count; -} - - -//============================================================================= -#ifndef PRODUCT -void BoxLockNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { - int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); - int reg = ra_->get_reg_first(this); - st->print("LEA [R_SP+#%d+BIAS],%s",offset,Matcher::regName[reg]); -} -#endif - -void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - C2_MacroAssembler _masm(&cbuf); - int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()) + STACK_BIAS; - int reg = ra_->get_encode(this); - - if (Assembler::is_simm13(offset)) { - __ add(SP, offset, reg_to_register_object(reg)); - } else { - __ set(offset, O7); - __ add(SP, O7, reg_to_register_object(reg)); - } -} - -uint BoxLockNode::size(PhaseRegAlloc *ra_) const { - // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_) - assert(ra_ == ra_->C->regalloc(), "sanity"); - return ra_->C->output()->scratch_emit_size(this); -} - -//============================================================================= -#ifndef PRODUCT -void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { - st->print_cr("\nUEP:"); - if (UseCompressedClassPointers) { - assert(Universe::heap() != NULL, "java heap should be initialized"); - st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass"); - if (CompressedKlassPointers::base() != 0) { - st->print_cr("\tSET CompressedKlassPointers::base,R_G6_heap_base"); - if (CompressedKlassPointers::shift() != 0) { - st->print_cr("\tSLL R_G5,CompressedKlassPointers::shift,R_G5"); - } - st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); - st->print_cr("\tSET CompressedOops::ptrs_base,R_G6_heap_base"); - } else { - st->print_cr("\tSLL R_G5,CompressedKlassPointers::shift,R_G5"); - } - } else { - st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check"); - } - st->print_cr("\tCMP R_G5,R_G3" ); - st->print ("\tTne xcc,R_G0+ST_RESERVED_FOR_USER_0+2"); -} -#endif - -void MachUEPNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { - C2_MacroAssembler _masm(&cbuf); - Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); - Register temp_reg = G3; - assert( G5_ic_reg != temp_reg, "conflicting registers" ); - - // Load klass from receiver - __ load_klass(O0, temp_reg); - // Compare against expected klass - __ cmp(temp_reg, G5_ic_reg); - // Branch to miss code, checks xcc or icc depending - __ trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0+2); -} - -uint MachUEPNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); -} - - -//============================================================================= - - -// Emit exception handler code. -int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) { - Register temp_reg = G3; - AddressLiteral exception_blob(OptoRuntime::exception_blob()->entry_point()); - C2_MacroAssembler _masm(&cbuf); - - address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return 0; // CodeBuffer::expand failed - } - - int offset = __ offset(); - - __ JUMP(exception_blob, temp_reg, 0); // sethi;jmp - __ delayed()->nop(); - - assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); - - __ end_a_stub(); - - return offset; -} - -int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { - // Can't use any of the current frame's registers as we may have deopted - // at a poll and everything (including G3) can be live. - Register temp_reg = L0; - AddressLiteral deopt_blob(SharedRuntime::deopt_blob()->unpack()); - C2_MacroAssembler _masm(&cbuf); - - address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return 0; // CodeBuffer::expand failed - } - - int offset = __ offset(); - __ save_frame(0); - __ JUMP(deopt_blob, temp_reg, 0); // sethi;jmp - __ delayed()->restore(); - - assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); - - __ end_a_stub(); - return offset; - -} - -// Given a register encoding, produce a Integer Register object -static Register reg_to_register_object(int register_encoding) { - assert(L5->encoding() == R_L5_enc && G1->encoding() == R_G1_enc, "right coding"); - return as_Register(register_encoding); -} - -// Given a register encoding, produce a single-precision Float Register object -static FloatRegister reg_to_SingleFloatRegister_object(int register_encoding) { - assert(F5->encoding(FloatRegisterImpl::S) == R_F5_enc && F12->encoding(FloatRegisterImpl::S) == R_F12_enc, "right coding"); - return as_SingleFloatRegister(register_encoding); -} - -// Given a register encoding, produce a double-precision Float Register object -static FloatRegister reg_to_DoubleFloatRegister_object(int register_encoding) { - assert(F4->encoding(FloatRegisterImpl::D) == R_F4_enc, "right coding"); - assert(F32->encoding(FloatRegisterImpl::D) == R_D32_enc, "right coding"); - return as_DoubleFloatRegister(register_encoding); -} - -const bool Matcher::match_rule_supported(int opcode) { - if (!has_match_rule(opcode)) - return false; - - switch (opcode) { - case Op_CountLeadingZerosI: - case Op_CountLeadingZerosL: - case Op_CountTrailingZerosI: - case Op_CountTrailingZerosL: - case Op_PopCountI: - case Op_PopCountL: - if (!UsePopCountInstruction) - return false; - case Op_CompareAndSwapL: - case Op_CompareAndSwapP: - if (!VM_Version::supports_cx8()) - return false; - break; - } - - return true; // Per default match rules are supported. -} - -const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { - - // TODO - // identify extra cases that we might want to provide match rules for - // e.g. Op_ vector nodes and other intrinsics while guarding with vlen - bool ret_value = match_rule_supported(opcode); - // Add rules here. - - return ret_value; // Per default match rules are supported. -} - -const bool Matcher::has_predicated_vectors(void) { - return false; -} - -const int Matcher::float_pressure(int default_pressure_threshold) { - return default_pressure_threshold; -} - -int Matcher::regnum_to_fpu_offset(int regnum) { - return regnum - 32; // The FP registers are in the second chunk -} - -#ifdef ASSERT -address last_rethrow = NULL; // debugging aid for Rethrow encoding -#endif - -// Vector width in bytes -const int Matcher::vector_width_in_bytes(BasicType bt) { - assert(MaxVectorSize == 8, ""); - return 8; -} - -// Vector ideal reg -const uint Matcher::vector_ideal_reg(int size) { - assert(MaxVectorSize == 8, ""); - return Op_RegD; -} - -// Limits on vector size (number of elements) loaded into vector. -const int Matcher::max_vector_size(const BasicType bt) { - assert(is_java_primitive(bt), "only primitive type vectors"); - return vector_width_in_bytes(bt)/type2aelembytes(bt); -} - -const int Matcher::min_vector_size(const BasicType bt) { - return max_vector_size(bt); // Same as max. -} - -// SPARC doesn't support misaligned vectors store/load. -const bool Matcher::misaligned_vectors_ok() { - return false; -} - -// Current (2013) SPARC platforms need to read original key -// to construct decryption expanded key -const bool Matcher::pass_original_key_for_aes() { - return true; -} - -// NOTE: All currently supported SPARC HW provides fast conversion. -const bool Matcher::convL2FSupported(void) { return true; } - -// Is this branch offset short enough that a short branch can be used? -// -// NOTE: If the platform does not provide any short branch variants, then -// this method should return false for offset 0. -bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { - // The passed offset is relative to address of the branch. - // Don't need to adjust the offset. - return UseCBCond && Assembler::is_simm12(offset); -} - -const bool Matcher::isSimpleConstant64(jlong value) { - // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. - // Depends on optimizations in MacroAssembler::setx. - int hi = (int)(value >> 32); - int lo = (int)(value & ~0); - return (hi == 0) || (hi == -1) || (lo == 0); -} - -// No scaling for the parameter the ClearArray node. -const bool Matcher::init_array_count_is_in_bytes = true; - -// No additional cost for CMOVL. -const int Matcher::long_cmove_cost() { return 0; } - -// CMOVF/CMOVD are expensive on e.g., T4 and SPARC64. -const int Matcher::float_cmove_cost() { - return VM_Version::has_fast_cmove() ? 0 : ConditionalMoveLimit; -} - -// Does the CPU require late expand (see block.cpp for description of late expand)? -const bool Matcher::require_postalloc_expand = false; - -// Do we need to mask the count passed to shift instructions or does -// the cpu only look at the lower 5/6 bits anyway? -const bool Matcher::need_masked_shift_count = false; - -// No support for generic vector operands. -const bool Matcher::supports_generic_vector_operands = false; - -MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { - ShouldNotReachHere(); // generic vector operands not supported - return NULL; -} - -bool Matcher::is_generic_reg2reg_move(MachNode* m) { - ShouldNotReachHere(); // generic vector operands not supported - return false; -} - -bool Matcher::is_generic_vector(MachOper* opnd) { - ShouldNotReachHere(); // generic vector operands not supported - return false; -} - -bool Matcher::narrow_oop_use_complex_address() { - assert(UseCompressedOops, "only for compressed oops code"); - return false; -} - -bool Matcher::narrow_klass_use_complex_address() { - assert(UseCompressedClassPointers, "only for compressed klass code"); - return false; -} - -bool Matcher::const_oop_prefer_decode() { - // TODO: Check if loading ConP from TOC in heap-based mode is better: - // Prefer ConN+DecodeN over ConP in simple compressed oops mode. - // return CompressedOops::base() == NULL; - return true; -} - -bool Matcher::const_klass_prefer_decode() { - // TODO: Check if loading ConP from TOC in heap-based mode is better: - // Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode. - // return CompressedKlassPointers::base() == NULL; - return true; -} - -// Is it better to copy float constants, or load them directly from memory? -// Intel can load a float constant from a direct address, requiring no -// extra registers. Most RISCs will have to materialize an address into a -// register first, so they would do better to copy the constant from stack. -const bool Matcher::rematerialize_float_constants = false; - -// If CPU can load and store mis-aligned doubles directly then no fixup is -// needed. Else we split the double into 2 integer pieces and move it -// piece-by-piece. Only happens when passing doubles into C code as the -// Java calling convention forces doubles to be aligned. -const bool Matcher::misaligned_doubles_ok = true; - -// No-op on SPARC. -void Matcher::pd_implicit_null_fixup(MachNode *node, uint idx) { -} - -// Advertise here if the CPU requires explicit rounding operations to implement strictfp mode. -const bool Matcher::strict_fp_requires_explicit_rounding = false; - -// Are floats converted to double when stored to stack during deoptimization? -// Sparc does not handle callee-save floats. -bool Matcher::float_in_double() { return false; } - -// Do ints take an entire long register or just half? -// Note that we if-def off of _LP64. -// The relevant question is how the int is callee-saved. In _LP64 -// the whole long is written but de-opt'ing will have to extract -// the relevant 32 bits, in not-_LP64 only the low 32 bits is written. -const bool Matcher::int_in_long = true; - -// Return whether or not this register is ever used as an argument. This -// function is used on startup to build the trampoline stubs in generateOptoStub. -// Registers not mentioned will be killed by the VM call in the trampoline, and -// arguments in those registers not be available to the callee. -bool Matcher::can_be_java_arg( int reg ) { - // Standard sparc 6 args in registers - if( reg == R_I0_num || - reg == R_I1_num || - reg == R_I2_num || - reg == R_I3_num || - reg == R_I4_num || - reg == R_I5_num ) return true; - // 64-bit builds can pass 64-bit pointers and longs in - // the high I registers - if( reg == R_I0H_num || - reg == R_I1H_num || - reg == R_I2H_num || - reg == R_I3H_num || - reg == R_I4H_num || - reg == R_I5H_num ) return true; - - if ((UseCompressedOops) && (reg == R_G6_num || reg == R_G6H_num)) { - return true; - } - - // A few float args in registers - if( reg >= R_F0_num && reg <= R_F7_num ) return true; - - return false; -} - -bool Matcher::is_spillable_arg( int reg ) { - return can_be_java_arg(reg); -} - -bool Matcher::use_asm_for_ldiv_by_con( jlong divisor ) { - // Use hardware SDIVX instruction when it is - // faster than a code which use multiply. - return VM_Version::has_fast_idiv(); -} - -// Register for DIVI projection of divmodI -RegMask Matcher::divI_proj_mask() { - ShouldNotReachHere(); - return RegMask(); -} - -// Register for MODI projection of divmodI -RegMask Matcher::modI_proj_mask() { - ShouldNotReachHere(); - return RegMask(); -} - -// Register for DIVL projection of divmodL -RegMask Matcher::divL_proj_mask() { - ShouldNotReachHere(); - return RegMask(); -} - -// Register for MODL projection of divmodL -RegMask Matcher::modL_proj_mask() { - ShouldNotReachHere(); - return RegMask(); -} - -const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return L7_REGP_mask(); -} - - -const bool Matcher::convi2l_type_required = true; - -// Should the matcher clone input 'm' of node 'n'? -bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { - return false; -} - -// Should the Matcher clone shifts on addressing modes, expecting them -// to be subsumed into complex addressing expressions or compute them -// into registers? -bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) { - return clone_base_plus_offset_address(m, mstack, address_visited); -} - -void Compile::reshape_address(AddPNode* addp) { -} - -%} - - -// The intptr_t operand types, defined by textual substitution. -// (Cf. opto/type.hpp. This lets us avoid many, many other ifdefs.) -#define immX immL -#define immX13 immL13 -#define immX13m7 immL13m7 -#define iRegX iRegL -#define g1RegX g1RegL - -//----------ENCODING BLOCK----------------------------------------------------- -// This block specifies the encoding classes used by the compiler to output -// byte streams. Encoding classes are parameterized macros used by -// Machine Instruction Nodes in order to generate the bit encoding of the -// instruction. Operands specify their base encoding interface with the -// interface keyword. There are currently supported four interfaces, -// REG_INTER, CONST_INTER, MEMORY_INTER, & COND_INTER. REG_INTER causes an -// operand to generate a function which returns its register number when -// queried. CONST_INTER causes an operand to generate a function which -// returns the value of the constant when queried. MEMORY_INTER causes an -// operand to generate four functions which return the Base Register, the -// Index Register, the Scale Value, and the Offset Value of the operand when -// queried. COND_INTER causes an operand to generate six functions which -// return the encoding code (ie - encoding bits for the instruction) -// associated with each basic boolean condition for a conditional instruction. -// -// Instructions specify two basic values for encoding. Again, a function -// is available to check if the constant displacement is an oop. They use the -// ins_encode keyword to specify their encoding classes (which must be -// a sequence of enc_class names, and their parameters, specified in -// the encoding block), and they use the -// opcode keyword to specify, in order, their primary, secondary, and -// tertiary opcode. Only the opcode sections which a particular instruction -// needs for encoding need to be specified. -encode %{ - enc_class enc_untested %{ -#ifdef ASSERT - C2_MacroAssembler _masm(&cbuf); - __ untested("encoding"); -#endif - %} - - enc_class form3_mem_reg( memory mem, iRegI dst ) %{ - emit_form3_mem_reg(cbuf, ra_, this, $primary, $tertiary, - $mem$$base, $mem$$disp, $mem$$index, $dst$$reg); - %} - - enc_class simple_form3_mem_reg( memory mem, iRegI dst ) %{ - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, - $mem$$base, $mem$$disp, $mem$$index, $dst$$reg); - %} - - enc_class form3_mem_prefetch_read( memory mem ) %{ - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, - $mem$$base, $mem$$disp, $mem$$index, 0/*prefetch function many-reads*/); - %} - - enc_class form3_mem_prefetch_write( memory mem ) %{ - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, - $mem$$base, $mem$$disp, $mem$$index, 2/*prefetch function many-writes*/); - %} - - enc_class form3_mem_reg_long_unaligned_marshal( memory mem, iRegL reg ) %{ - assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4"); - assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4"); - guarantee($mem$$index == R_G0_enc, "double index?"); - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, R_O7_enc ); - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg ); - emit3_simm13( cbuf, Assembler::arith_op, $reg$$reg, Assembler::sllx_op3, $reg$$reg, 0x1020 ); - emit3( cbuf, Assembler::arith_op, $reg$$reg, Assembler::or_op3, $reg$$reg, 0, R_O7_enc ); - %} - - enc_class form3_mem_reg_double_unaligned( memory mem, RegD_low reg ) %{ - assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4"); - assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4"); - guarantee($mem$$index == R_G0_enc, "double index?"); - // Load long with 2 instructions - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg+0 ); - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, $reg$$reg+1 ); - %} - - //%%% form3_mem_plus_4_reg is a hack--get rid of it - enc_class form3_mem_plus_4_reg( memory mem, iRegI dst ) %{ - guarantee($mem$$disp, "cannot offset a reg-reg operand by 4"); - emit_form3_mem_reg(cbuf, ra_, this, $primary, -1, $mem$$base, $mem$$disp + 4, $mem$$index, $dst$$reg); - %} - - enc_class form3_g0_rs2_rd_move( iRegI rs2, iRegI rd ) %{ - // Encode a reg-reg copy. If it is useless, then empty encoding. - if( $rs2$$reg != $rd$$reg ) - emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0, $rs2$$reg ); - %} - - // Target lo half of long - enc_class form3_g0_rs2_rd_move_lo( iRegI rs2, iRegL rd ) %{ - // Encode a reg-reg copy. If it is useless, then empty encoding. - if( $rs2$$reg != LONG_LO_REG($rd$$reg) ) - emit3( cbuf, Assembler::arith_op, LONG_LO_REG($rd$$reg), Assembler::or_op3, 0, 0, $rs2$$reg ); - %} - - // Source lo half of long - enc_class form3_g0_rs2_rd_move_lo2( iRegL rs2, iRegI rd ) %{ - // Encode a reg-reg copy. If it is useless, then empty encoding. - if( LONG_LO_REG($rs2$$reg) != $rd$$reg ) - emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0, LONG_LO_REG($rs2$$reg) ); - %} - - // Target hi half of long - enc_class form3_rs1_rd_copysign_hi( iRegI rs1, iRegL rd ) %{ - emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::sra_op3, $rs1$$reg, 31 ); - %} - - // Source lo half of long, and leave it sign extended. - enc_class form3_rs1_rd_signextend_lo1( iRegL rs1, iRegI rd ) %{ - // Sign extend low half - emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::sra_op3, $rs1$$reg, 0, 0 ); - %} - - // Source hi half of long, and leave it sign extended. - enc_class form3_rs1_rd_copy_hi1( iRegL rs1, iRegI rd ) %{ - // Shift high half to low half - emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::srlx_op3, $rs1$$reg, 32 ); - %} - - // Source hi half of long - enc_class form3_g0_rs2_rd_move_hi2( iRegL rs2, iRegI rd ) %{ - // Encode a reg-reg copy. If it is useless, then empty encoding. - if( LONG_HI_REG($rs2$$reg) != $rd$$reg ) - emit3( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, 0, LONG_HI_REG($rs2$$reg) ); - %} - - enc_class form3_rs1_rs2_rd( iRegI rs1, iRegI rs2, iRegI rd ) %{ - emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, 0, $rs2$$reg ); - %} - - enc_class enc_to_bool( iRegI src, iRegI dst ) %{ - emit3 ( cbuf, Assembler::arith_op, 0, Assembler::subcc_op3, 0, 0, $src$$reg ); - emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::addc_op3 , 0, 0 ); - %} - - enc_class enc_ltmask( iRegI p, iRegI q, iRegI dst ) %{ - emit3 ( cbuf, Assembler::arith_op, 0, Assembler::subcc_op3, $p$$reg, 0, $q$$reg ); - // clear if nothing else is happening - emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, 0 ); - // blt,a,pn done - emit2_19 ( cbuf, Assembler::branch_op, 1/*annul*/, Assembler::less, Assembler::bp_op2, Assembler::icc, 0/*predict not taken*/, 2 ); - // mov dst,-1 in delay slot - emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, -1 ); - %} - - enc_class form3_rs1_imm5_rd( iRegI rs1, immU5 imm5, iRegI rd ) %{ - emit3_simm13( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $imm5$$constant & 0x1F ); - %} - - enc_class form3_sd_rs1_imm6_rd( iRegL rs1, immU6 imm6, iRegL rd ) %{ - emit3_simm13( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, ($imm6$$constant & 0x3F) | 0x1000 ); - %} - - enc_class form3_sd_rs1_rs2_rd( iRegL rs1, iRegI rs2, iRegL rd ) %{ - emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, 0x80, $rs2$$reg ); - %} - - enc_class form3_rs1_simm13_rd( iRegI rs1, immI13 simm13, iRegI rd ) %{ - emit3_simm13( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $simm13$$constant ); - %} - - enc_class move_return_pc_to_o1() %{ - emit3_simm13( cbuf, Assembler::arith_op, R_O1_enc, Assembler::add_op3, R_O7_enc, frame::pc_return_offset ); - %} - - /* %%% merge with enc_to_bool */ - enc_class enc_convP2B( iRegI dst, iRegP src ) %{ - C2_MacroAssembler _masm(&cbuf); - - Register src_reg = reg_to_register_object($src$$reg); - Register dst_reg = reg_to_register_object($dst$$reg); - __ movr(Assembler::rc_nz, src_reg, 1, dst_reg); - %} - - enc_class enc_cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, iRegI tmp ) %{ - // (Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q))) - C2_MacroAssembler _masm(&cbuf); - - Register p_reg = reg_to_register_object($p$$reg); - Register q_reg = reg_to_register_object($q$$reg); - Register y_reg = reg_to_register_object($y$$reg); - Register tmp_reg = reg_to_register_object($tmp$$reg); - - __ subcc( p_reg, q_reg, p_reg ); - __ add ( p_reg, y_reg, tmp_reg ); - __ movcc( Assembler::less, false, Assembler::icc, tmp_reg, p_reg ); - %} - - enc_class form_d2i_helper(regD src, regF dst) %{ - // fcmp %fcc0,$src,$src - emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmpd_opf, $src$$reg ); - // branch %fcc0 not-nan, predict taken - emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 ); - // fdtoi $src,$dst - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fdtoi_opf, $src$$reg ); - // fitos $dst,$dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fitos_opf, $dst$$reg ); - // clear $dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubs_opf, $dst$$reg ); - // carry on here... - %} - - enc_class form_d2l_helper(regD src, regD dst) %{ - // fcmp %fcc0,$src,$src check for NAN - emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmpd_opf, $src$$reg ); - // branch %fcc0 not-nan, predict taken - emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 ); - // fdtox $src,$dst convert in delay slot - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fdtox_opf, $src$$reg ); - // fxtod $dst,$dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fxtod_opf, $dst$$reg ); - // clear $dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubd_opf, $dst$$reg ); - // carry on here... - %} - - enc_class form_f2i_helper(regF src, regF dst) %{ - // fcmps %fcc0,$src,$src - emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmps_opf, $src$$reg ); - // branch %fcc0 not-nan, predict taken - emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 ); - // fstoi $src,$dst - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fstoi_opf, $src$$reg ); - // fitos $dst,$dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fitos_opf, $dst$$reg ); - // clear $dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubs_opf, $dst$$reg ); - // carry on here... - %} - - enc_class form_f2l_helper(regF src, regD dst) %{ - // fcmps %fcc0,$src,$src - emit3( cbuf, Assembler::arith_op , Assembler::fcc0, Assembler::fpop2_op3, $src$$reg, Assembler::fcmps_opf, $src$$reg ); - // branch %fcc0 not-nan, predict taken - emit2_19( cbuf, Assembler::branch_op, 0/*annul*/, Assembler::f_ordered, Assembler::fbp_op2, Assembler::fcc0, 1/*predict taken*/, 4 ); - // fstox $src,$dst - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fstox_opf, $src$$reg ); - // fxtod $dst,$dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, 0, Assembler::fxtod_opf, $dst$$reg ); - // clear $dst (if nan) - emit3( cbuf, Assembler::arith_op , $dst$$reg, Assembler::fpop1_op3, $dst$$reg, Assembler::fsubd_opf, $dst$$reg ); - // carry on here... - %} - - enc_class form3_opf_rs2F_rdF(regF rs2, regF rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %} - enc_class form3_opf_rs2F_rdD(regF rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %} - enc_class form3_opf_rs2D_rdF(regD rs2, regF rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %} - enc_class form3_opf_rs2D_rdD(regD rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %} - - enc_class form3_opf_rs2D_lo_rdF(regD rs2, regF rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg+1); %} - - enc_class form3_opf_rs2D_hi_rdD_hi(regD rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg,$primary,0,$tertiary,$rs2$$reg); %} - enc_class form3_opf_rs2D_lo_rdD_lo(regD rs2, regD rd) %{ emit3(cbuf,$secondary,$rd$$reg+1,$primary,0,$tertiary,$rs2$$reg+1); %} - - enc_class form3_opf_rs1F_rs2F_rdF( regF rs1, regF rs2, regF rd ) %{ - emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg ); - %} - - enc_class form3_opf_rs1D_rs2D_rdD( regD rs1, regD rs2, regD rd ) %{ - emit3( cbuf, $secondary, $rd$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg ); - %} - - enc_class form3_opf_rs1F_rs2F_fcc( regF rs1, regF rs2, flagsRegF fcc ) %{ - emit3( cbuf, $secondary, $fcc$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg ); - %} - - enc_class form3_opf_rs1D_rs2D_fcc( regD rs1, regD rs2, flagsRegF fcc ) %{ - emit3( cbuf, $secondary, $fcc$$reg, $primary, $rs1$$reg, $tertiary, $rs2$$reg ); - %} - - enc_class form3_convI2F(regF rs2, regF rd) %{ - emit3(cbuf,Assembler::arith_op,$rd$$reg,Assembler::fpop1_op3,0,$secondary,$rs2$$reg); - %} - - // Encloding class for traceable jumps - enc_class form_jmpl(g3RegP dest) %{ - emit_jmpl(cbuf, $dest$$reg); - %} - - enc_class form_jmpl_set_exception_pc(g1RegP dest) %{ - emit_jmpl_set_exception_pc(cbuf, $dest$$reg); - %} - - enc_class form2_nop() %{ - emit_nop(cbuf); - %} - - enc_class form2_illtrap() %{ - emit_illtrap(cbuf); - %} - - - // Compare longs and convert into -1, 0, 1. - enc_class cmpl_flag( iRegL src1, iRegL src2, iRegI dst ) %{ - // CMP $src1,$src2 - emit3( cbuf, Assembler::arith_op, 0, Assembler::subcc_op3, $src1$$reg, 0, $src2$$reg ); - // blt,a,pn done - emit2_19( cbuf, Assembler::branch_op, 1/*annul*/, Assembler::less , Assembler::bp_op2, Assembler::xcc, 0/*predict not taken*/, 5 ); - // mov dst,-1 in delay slot - emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, -1 ); - // bgt,a,pn done - emit2_19( cbuf, Assembler::branch_op, 1/*annul*/, Assembler::greater, Assembler::bp_op2, Assembler::xcc, 0/*predict not taken*/, 3 ); - // mov dst,1 in delay slot - emit3_simm13( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3, 0, 1 ); - // CLR $dst - emit3( cbuf, Assembler::arith_op, $dst$$reg, Assembler::or_op3 , 0, 0, 0 ); - %} - - enc_class enc_PartialSubtypeCheck() %{ - C2_MacroAssembler _masm(&cbuf); - __ call(StubRoutines::Sparc::partial_subtype_check(), relocInfo::runtime_call_type); - __ delayed()->nop(); - %} - - enc_class enc_bp( label labl, cmpOp cmp, flagsReg cc ) %{ - C2_MacroAssembler _masm(&cbuf); - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - - __ bp( (Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - - enc_class enc_bpr( label labl, cmpOp_reg cmp, iRegI op1 ) %{ - C2_MacroAssembler _masm(&cbuf); - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - - __ bpr( (Assembler::RCondition)($cmp$$cmpcode), false, predict_taken, as_Register($op1$$reg), *L); - __ delayed()->nop(); - %} - - enc_class enc_cmov_reg( cmpOp cmp, iRegI dst, iRegI src, immI pcc) %{ - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::movcc_op3 << 19) | - (1 << 18) | // cc2 bit for 'icc' - ($cmp$$cmpcode << 14) | - (0 << 13) | // select register move - ($pcc$$constant << 11) | // cc1, cc0 bits for 'icc' or 'xcc' - ($src$$reg << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class enc_cmov_imm( cmpOp cmp, iRegI dst, immI11 src, immI pcc ) %{ - int simm11 = $src$$constant & ((1<<11)-1); // Mask to 11 bits - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::movcc_op3 << 19) | - (1 << 18) | // cc2 bit for 'icc' - ($cmp$$cmpcode << 14) | - (1 << 13) | // select immediate move - ($pcc$$constant << 11) | // cc1, cc0 bits for 'icc' - (simm11 << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class enc_cmov_reg_f( cmpOpF cmp, iRegI dst, iRegI src, flagsRegF fcc ) %{ - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::movcc_op3 << 19) | - (0 << 18) | // cc2 bit for 'fccX' - ($cmp$$cmpcode << 14) | - (0 << 13) | // select register move - ($fcc$$reg << 11) | // cc1, cc0 bits for fcc0-fcc3 - ($src$$reg << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class enc_cmov_imm_f( cmpOp cmp, iRegI dst, immI11 src, flagsRegF fcc ) %{ - int simm11 = $src$$constant & ((1<<11)-1); // Mask to 11 bits - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::movcc_op3 << 19) | - (0 << 18) | // cc2 bit for 'fccX' - ($cmp$$cmpcode << 14) | - (1 << 13) | // select immediate move - ($fcc$$reg << 11) | // cc1, cc0 bits for fcc0-fcc3 - (simm11 << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class enc_cmovf_reg( cmpOp cmp, regD dst, regD src, immI pcc ) %{ - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::fpop2_op3 << 19) | - (0 << 18) | - ($cmp$$cmpcode << 14) | - (1 << 13) | // select register move - ($pcc$$constant << 11) | // cc1-cc0 bits for 'icc' or 'xcc' - ($primary << 5) | // select single, double or quad - ($src$$reg << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class enc_cmovff_reg( cmpOpF cmp, flagsRegF fcc, regD dst, regD src ) %{ - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::fpop2_op3 << 19) | - (0 << 18) | - ($cmp$$cmpcode << 14) | - ($fcc$$reg << 11) | // cc2-cc0 bits for 'fccX' - ($primary << 5) | // select single, double or quad - ($src$$reg << 0); - cbuf.insts()->emit_int32(op); - %} - - // Used by the MIN/MAX encodings. Same as a CMOV, but - // the condition comes from opcode-field instead of an argument. - enc_class enc_cmov_reg_minmax( iRegI dst, iRegI src ) %{ - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::movcc_op3 << 19) | - (1 << 18) | // cc2 bit for 'icc' - ($primary << 14) | - (0 << 13) | // select register move - (0 << 11) | // cc1, cc0 bits for 'icc' - ($src$$reg << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class enc_cmov_reg_minmax_long( iRegL dst, iRegL src ) %{ - int op = (Assembler::arith_op << 30) | - ($dst$$reg << 25) | - (Assembler::movcc_op3 << 19) | - (6 << 16) | // cc2 bit for 'xcc' - ($primary << 14) | - (0 << 13) | // select register move - (0 << 11) | // cc1, cc0 bits for 'icc' - ($src$$reg << 0); - cbuf.insts()->emit_int32(op); - %} - - enc_class Set13( immI13 src, iRegI rd ) %{ - emit3_simm13( cbuf, Assembler::arith_op, $rd$$reg, Assembler::or_op3, 0, $src$$constant ); - %} - - enc_class SetHi22( immI src, iRegI rd ) %{ - emit2_22( cbuf, Assembler::branch_op, $rd$$reg, Assembler::sethi_op2, $src$$constant ); - %} - - enc_class Set32( immI src, iRegI rd ) %{ - C2_MacroAssembler _masm(&cbuf); - __ set($src$$constant, reg_to_register_object($rd$$reg)); - %} - - enc_class call_epilog %{ - if( VerifyStackAtCalls ) { - C2_MacroAssembler _masm(&cbuf); - int framesize = ra_->C->output()->frame_size_in_bytes(); - Register temp_reg = G3; - __ add(SP, framesize, temp_reg); - __ cmp(temp_reg, FP); - __ breakpoint_trap(Assembler::notEqual, Assembler::ptr_cc); - } - %} - - // Long values come back from native calls in O0:O1 in the 32-bit VM, copy the value - // to G1 so the register allocator will not have to deal with the misaligned register - // pair. - enc_class adjust_long_from_native_call %{ - %} - - enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime - // CALL directly to the runtime - // The user of this is responsible for ensuring that R_L7 is empty (killed). - emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec(), /*preserve_g2=*/true); - %} - - enc_class preserve_SP %{ - C2_MacroAssembler _masm(&cbuf); - __ mov(SP, L7_mh_SP_save); - %} - - enc_class restore_SP %{ - C2_MacroAssembler _masm(&cbuf); - __ mov(L7_mh_SP_save, SP); - %} - - enc_class Java_Static_Call (method meth) %{ // JAVA STATIC CALL - // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine - // who we intended to call. - if (!_method) { - emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec()); - } else { - int method_index = resolved_method_index(cbuf); - RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) - : static_call_Relocation::spec(method_index); - emit_call_reloc(cbuf, $meth$$method, rspec); - - // Emit stub for static call. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); - if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } - } - %} - - enc_class Java_Dynamic_Call (method meth) %{ // JAVA DYNAMIC CALL - C2_MacroAssembler _masm(&cbuf); - __ set_inst_mark(); - int vtable_index = this->_vtable_index; - // MachCallDynamicJavaNode::ret_addr_offset uses this same test - if (vtable_index < 0) { - // must be invalid_vtable_index, not nonvirtual_vtable_index - assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value"); - Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); - assert(G5_ic_reg == G5_inline_cache_reg, "G5_inline_cache_reg used in assemble_ic_buffer_code()"); - assert(G5_ic_reg == G5_megamorphic_method, "G5_megamorphic_method used in megamorphic call stub"); - __ ic_call((address)$meth$$method, /*emit_delay=*/true, resolved_method_index(cbuf)); - } else { - assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); - // Just go thru the vtable - // get receiver klass (receiver already checked for non-null) - // If we end up going thru a c2i adapter interpreter expects method in G5 - int off = __ offset(); - __ load_klass(O0, G3_scratch); - int klass_load_size; - if (UseCompressedClassPointers) { - assert(Universe::heap() != NULL, "java heap should be initialized"); - klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord; - } else { - klass_load_size = 1*BytesPerInstWord; - } - int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes(); - int v_off = entry_offset + vtableEntry::method_offset_in_bytes(); - if (Assembler::is_simm13(v_off)) { - __ ld_ptr(G3, v_off, G5_method); - } else { - // Generate 2 instructions - __ Assembler::sethi(v_off & ~0x3ff, G5_method); - __ or3(G5_method, v_off & 0x3ff, G5_method); - // ld_ptr, set_hi, set - assert(__ offset() - off == klass_load_size + 2*BytesPerInstWord, - "Unexpected instruction size(s)"); - __ ld_ptr(G3, G5_method, G5_method); - } - // NOTE: for vtable dispatches, the vtable entry will never be null. - // However it may very well end up in handle_wrong_method if the - // method is abstract for the particular class. - __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); - // jump to target (either compiled code or c2iadapter) - __ jmpl(G3_scratch, G0, O7); - __ delayed()->nop(); - } - %} - - enc_class Java_Compiled_Call (method meth) %{ // JAVA COMPILED CALL - C2_MacroAssembler _masm(&cbuf); - - Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); - Register temp_reg = G3; // caller must kill G3! We cannot reuse G5_ic_reg here because - // we might be calling a C2I adapter which needs it. - - assert(temp_reg != G5_ic_reg, "conflicting registers"); - // Load nmethod - __ ld_ptr(G5_ic_reg, in_bytes(Method::from_compiled_offset()), temp_reg); - - // CALL to compiled java, indirect the contents of G3 - __ set_inst_mark(); - __ callr(temp_reg, G0); - __ delayed()->nop(); - %} - -enc_class idiv_reg(iRegIsafe src1, iRegIsafe src2, iRegIsafe dst) %{ - C2_MacroAssembler _masm(&cbuf); - Register Rdividend = reg_to_register_object($src1$$reg); - Register Rdivisor = reg_to_register_object($src2$$reg); - Register Rresult = reg_to_register_object($dst$$reg); - - __ sra(Rdivisor, 0, Rdivisor); - __ sra(Rdividend, 0, Rdividend); - __ sdivx(Rdividend, Rdivisor, Rresult); -%} - -enc_class idiv_imm(iRegIsafe src1, immI13 imm, iRegIsafe dst) %{ - C2_MacroAssembler _masm(&cbuf); - - Register Rdividend = reg_to_register_object($src1$$reg); - int divisor = $imm$$constant; - Register Rresult = reg_to_register_object($dst$$reg); - - __ sra(Rdividend, 0, Rdividend); - __ sdivx(Rdividend, divisor, Rresult); -%} - -enc_class enc_mul_hi(iRegIsafe dst, iRegIsafe src1, iRegIsafe src2) %{ - C2_MacroAssembler _masm(&cbuf); - Register Rsrc1 = reg_to_register_object($src1$$reg); - Register Rsrc2 = reg_to_register_object($src2$$reg); - Register Rdst = reg_to_register_object($dst$$reg); - - __ sra( Rsrc1, 0, Rsrc1 ); - __ sra( Rsrc2, 0, Rsrc2 ); - __ mulx( Rsrc1, Rsrc2, Rdst ); - __ srlx( Rdst, 32, Rdst ); -%} - -enc_class irem_reg(iRegIsafe src1, iRegIsafe src2, iRegIsafe dst, o7RegL scratch) %{ - C2_MacroAssembler _masm(&cbuf); - Register Rdividend = reg_to_register_object($src1$$reg); - Register Rdivisor = reg_to_register_object($src2$$reg); - Register Rresult = reg_to_register_object($dst$$reg); - Register Rscratch = reg_to_register_object($scratch$$reg); - - assert(Rdividend != Rscratch, ""); - assert(Rdivisor != Rscratch, ""); - - __ sra(Rdividend, 0, Rdividend); - __ sra(Rdivisor, 0, Rdivisor); - __ sdivx(Rdividend, Rdivisor, Rscratch); - __ mulx(Rscratch, Rdivisor, Rscratch); - __ sub(Rdividend, Rscratch, Rresult); -%} - -enc_class irem_imm(iRegIsafe src1, immI13 imm, iRegIsafe dst, o7RegL scratch) %{ - C2_MacroAssembler _masm(&cbuf); - - Register Rdividend = reg_to_register_object($src1$$reg); - int divisor = $imm$$constant; - Register Rresult = reg_to_register_object($dst$$reg); - Register Rscratch = reg_to_register_object($scratch$$reg); - - assert(Rdividend != Rscratch, ""); - - __ sra(Rdividend, 0, Rdividend); - __ sdivx(Rdividend, divisor, Rscratch); - __ mulx(Rscratch, divisor, Rscratch); - __ sub(Rdividend, Rscratch, Rresult); -%} - -enc_class fabss (sflt_reg dst, sflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_SingleFloatRegister_object($src$$reg); - - __ fabs(FloatRegisterImpl::S, Fsrc, Fdst); -%} - -enc_class fabsd (dflt_reg dst, dflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg); - - __ fabs(FloatRegisterImpl::D, Fsrc, Fdst); -%} - -enc_class fnegd (dflt_reg dst, dflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg); - - __ fneg(FloatRegisterImpl::D, Fsrc, Fdst); -%} - -enc_class fsqrts (sflt_reg dst, sflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_SingleFloatRegister_object($src$$reg); - - __ fsqrt(FloatRegisterImpl::S, Fsrc, Fdst); -%} - -enc_class fsqrtd (dflt_reg dst, dflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg); - - __ fsqrt(FloatRegisterImpl::D, Fsrc, Fdst); -%} - - -enc_class fmadds (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); - - __ fmadd(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); -%} - -enc_class fmaddd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); - - __ fmadd(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); -%} - -enc_class fmsubs (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); - - __ fmsub(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); -%} - -enc_class fmsubd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); - - __ fmsub(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); -%} - -enc_class fnmadds (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); - - __ fnmadd(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); -%} - -enc_class fnmaddd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); - - __ fnmadd(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); -%} - -enc_class fnmsubs (sflt_reg dst, sflt_reg a, sflt_reg b, sflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_SingleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_SingleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_SingleFloatRegister_object($c$$reg); - - __ fnmsub(FloatRegisterImpl::S, Fra, Frb, Frc, Frd); -%} - -enc_class fnmsubd (dflt_reg dst, dflt_reg a, dflt_reg b, dflt_reg c) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Frd = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fra = reg_to_DoubleFloatRegister_object($a$$reg); - FloatRegister Frb = reg_to_DoubleFloatRegister_object($b$$reg); - FloatRegister Frc = reg_to_DoubleFloatRegister_object($c$$reg); - - __ fnmsub(FloatRegisterImpl::D, Fra, Frb, Frc, Frd); -%} - - -enc_class fmovs (dflt_reg dst, dflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_SingleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_SingleFloatRegister_object($src$$reg); - - __ fmov(FloatRegisterImpl::S, Fsrc, Fdst); -%} - -enc_class fmovd (dflt_reg dst, dflt_reg src) %{ - C2_MacroAssembler _masm(&cbuf); - - FloatRegister Fdst = reg_to_DoubleFloatRegister_object($dst$$reg); - FloatRegister Fsrc = reg_to_DoubleFloatRegister_object($src$$reg); - - __ fmov(FloatRegisterImpl::D, Fsrc, Fdst); -%} - -enc_class Fast_Lock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{ - C2_MacroAssembler _masm(&cbuf); - - Register Roop = reg_to_register_object($oop$$reg); - Register Rbox = reg_to_register_object($box$$reg); - Register Rscratch = reg_to_register_object($scratch$$reg); - Register Rmark = reg_to_register_object($scratch2$$reg); - - assert(Roop != Rscratch, ""); - assert(Roop != Rmark, ""); - assert(Rbox != Rscratch, ""); - assert(Rbox != Rmark, ""); - - __ compiler_lock_object(Roop, Rmark, Rbox, Rscratch, _counters, UseBiasedLocking && !UseOptoBiasInlining); -%} - -enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{ - C2_MacroAssembler _masm(&cbuf); - - Register Roop = reg_to_register_object($oop$$reg); - Register Rbox = reg_to_register_object($box$$reg); - Register Rscratch = reg_to_register_object($scratch$$reg); - Register Rmark = reg_to_register_object($scratch2$$reg); - - assert(Roop != Rscratch, ""); - assert(Roop != Rmark, ""); - assert(Rbox != Rscratch, ""); - assert(Rbox != Rmark, ""); - - __ compiler_unlock_object(Roop, Rmark, Rbox, Rscratch, UseBiasedLocking && !UseOptoBiasInlining); - %} - - enc_class enc_cas( iRegP mem, iRegP old, iRegP new ) %{ - C2_MacroAssembler _masm(&cbuf); - Register Rmem = reg_to_register_object($mem$$reg); - Register Rold = reg_to_register_object($old$$reg); - Register Rnew = reg_to_register_object($new$$reg); - - __ cas_ptr(Rmem, Rold, Rnew); // Swap(*Rmem,Rnew) if *Rmem == Rold - __ cmp( Rold, Rnew ); - %} - - enc_class enc_casx( iRegP mem, iRegL old, iRegL new) %{ - Register Rmem = reg_to_register_object($mem$$reg); - Register Rold = reg_to_register_object($old$$reg); - Register Rnew = reg_to_register_object($new$$reg); - - C2_MacroAssembler _masm(&cbuf); - __ mov(Rnew, O7); - __ casx(Rmem, Rold, O7); - __ cmp( Rold, O7 ); - %} - - // raw int cas, used for compareAndSwap - enc_class enc_casi( iRegP mem, iRegL old, iRegL new) %{ - Register Rmem = reg_to_register_object($mem$$reg); - Register Rold = reg_to_register_object($old$$reg); - Register Rnew = reg_to_register_object($new$$reg); - - C2_MacroAssembler _masm(&cbuf); - __ mov(Rnew, O7); - __ cas(Rmem, Rold, O7); - __ cmp( Rold, O7 ); - %} - - // raw int cas without using tmp register for compareAndExchange - enc_class enc_casi_exch( iRegP mem, iRegL old, iRegL new) %{ - Register Rmem = reg_to_register_object($mem$$reg); - Register Rold = reg_to_register_object($old$$reg); - Register Rnew = reg_to_register_object($new$$reg); - - C2_MacroAssembler _masm(&cbuf); - __ cas(Rmem, Rold, Rnew); - %} - - // 64-bit cas without using tmp register for compareAndExchange - enc_class enc_casx_exch( iRegP mem, iRegL old, iRegL new) %{ - Register Rmem = reg_to_register_object($mem$$reg); - Register Rold = reg_to_register_object($old$$reg); - Register Rnew = reg_to_register_object($new$$reg); - - C2_MacroAssembler _masm(&cbuf); - __ casx(Rmem, Rold, Rnew); - %} - - enc_class enc_lflags_ne_to_boolean( iRegI res ) %{ - Register Rres = reg_to_register_object($res$$reg); - - C2_MacroAssembler _masm(&cbuf); - __ mov(1, Rres); - __ movcc( Assembler::notEqual, false, Assembler::xcc, G0, Rres ); - %} - - enc_class enc_iflags_ne_to_boolean( iRegI res ) %{ - Register Rres = reg_to_register_object($res$$reg); - - C2_MacroAssembler _masm(&cbuf); - __ mov(1, Rres); - __ movcc( Assembler::notEqual, false, Assembler::icc, G0, Rres ); - %} - - enc_class floating_cmp ( iRegP dst, regF src1, regF src2 ) %{ - C2_MacroAssembler _masm(&cbuf); - Register Rdst = reg_to_register_object($dst$$reg); - FloatRegister Fsrc1 = $primary ? reg_to_SingleFloatRegister_object($src1$$reg) - : reg_to_DoubleFloatRegister_object($src1$$reg); - FloatRegister Fsrc2 = $primary ? reg_to_SingleFloatRegister_object($src2$$reg) - : reg_to_DoubleFloatRegister_object($src2$$reg); - - // Convert condition code fcc0 into -1,0,1; unordered reports less-than (-1) - __ float_cmp( $primary, -1, Fsrc1, Fsrc2, Rdst); - %} - - enc_class enc_rethrow() %{ - cbuf.set_insts_mark(); - Register temp_reg = G3; - AddressLiteral rethrow_stub(OptoRuntime::rethrow_stub()); - assert(temp_reg != reg_to_register_object(R_I0_num), "temp must not break oop_reg"); - C2_MacroAssembler _masm(&cbuf); -#ifdef ASSERT - __ save_frame(0); - AddressLiteral last_rethrow_addrlit(&last_rethrow); - __ sethi(last_rethrow_addrlit, L1); - Address addr(L1, last_rethrow_addrlit.low10()); - __ rdpc(L2); - __ inc(L2, 3 * BytesPerInstWord); // skip this & 2 more insns to point at jump_to - __ st_ptr(L2, addr); - __ restore(); -#endif - __ JUMP(rethrow_stub, temp_reg, 0); // sethi;jmp - __ delayed()->nop(); - %} - - enc_class emit_mem_nop() %{ - // Generates the instruction LDUXA [o6,g0],#0x82,g0 - cbuf.insts()->emit_int32((unsigned int) 0xc0839040); - %} - - enc_class emit_fadd_nop() %{ - // Generates the instruction FMOVS f31,f31 - cbuf.insts()->emit_int32((unsigned int) 0xbfa0003f); - %} - - enc_class emit_br_nop() %{ - // Generates the instruction BPN,PN . - cbuf.insts()->emit_int32((unsigned int) 0x00400000); - %} - - enc_class enc_membar_acquire %{ - C2_MacroAssembler _masm(&cbuf); - __ membar( Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::LoadLoad) ); - %} - - enc_class enc_membar_release %{ - C2_MacroAssembler _masm(&cbuf); - __ membar( Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore) ); - %} - - enc_class enc_membar_volatile %{ - C2_MacroAssembler _masm(&cbuf); - __ membar( Assembler::Membar_mask_bits(Assembler::StoreLoad) ); - %} - -%} - -//----------FRAME-------------------------------------------------------------- -// Definition of frame structure and management information. -// -// S T A C K L A Y O U T Allocators stack-slot number -// | (to get allocators register number -// G Owned by | | v add VMRegImpl::stack0) -// r CALLER | | -// o | +--------+ pad to even-align allocators stack-slot -// w V | pad0 | numbers; owned by CALLER -// t -----------+--------+----> Matcher::_in_arg_limit, unaligned -// h ^ | in | 5 -// | | args | 4 Holes in incoming args owned by SELF -// | | | | 3 -// | | +--------+ -// V | | old out| Empty on Intel, window on Sparc -// | old |preserve| Must be even aligned. -// | SP-+--------+----> Matcher::_old_SP, 8 (or 16 in LP64)-byte aligned -// | | in | 3 area for Intel ret address -// Owned by |preserve| Empty on Sparc. -// SELF +--------+ -// | | pad2 | 2 pad to align old SP -// | +--------+ 1 -// | | locks | 0 -// | +--------+----> VMRegImpl::stack0, 8 (or 16 in LP64)-byte aligned -// | | pad1 | 11 pad to align new SP -// | +--------+ -// | | | 10 -// | | spills | 9 spills -// V | | 8 (pad0 slot for callee) -// -----------+--------+----> Matcher::_out_arg_limit, unaligned -// ^ | out | 7 -// | | args | 6 Holes in outgoing args owned by CALLEE -// Owned by +--------+ -// CALLEE | new out| 6 Empty on Intel, window on Sparc -// | new |preserve| Must be even-aligned. -// | SP-+--------+----> Matcher::_new_SP, even aligned -// | | | -// -// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is -// known from SELF's arguments and the Java calling convention. -// Region 6-7 is determined per call site. -// Note 2: If the calling convention leaves holes in the incoming argument -// area, those holes are owned by SELF. Holes in the outgoing area -// are owned by the CALLEE. Holes should not be nessecary in the -// incoming area, as the Java calling convention is completely under -// the control of the AD file. Doubles can be sorted and packed to -// avoid holes. Holes in the outgoing arguments may be necessary for -// varargs C calling conventions. -// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is -// even aligned with pad0 as needed. -// Region 6 is even aligned. Region 6-7 is NOT even aligned; -// region 6-11 is even aligned; it may be padded out more so that -// the region from SP to FP meets the minimum stack alignment. - -frame %{ - // What direction does stack grow in (assumed to be same for native & Java) - stack_direction(TOWARDS_LOW); - - // These two registers define part of the calling convention - // between compiled code and the interpreter. - inline_cache_reg(R_G5); // Inline Cache Register or Method* for I2C - interpreter_method_oop_reg(R_G5); // Method Oop Register when calling interpreter - - // Optional: name the operand used by cisc-spilling to access [stack_pointer + offset] - cisc_spilling_operand_name(indOffset); - - // Number of stack slots consumed by a Monitor enter - sync_stack_slots(2); - - // Compiled code's Frame Pointer - frame_pointer(R_SP); - - // Stack alignment requirement - stack_alignment(StackAlignmentInBytes); - // LP64: Alignment size in bytes (128-bit -> 16 bytes) - // !LP64: Alignment size in bytes (64-bit -> 8 bytes) - - // Number of stack slots between incoming argument block and the start of - // a new frame. The PROLOG must add this many slots to the stack. The - // EPILOG must remove this many slots. - in_preserve_stack_slots(0); - - // Number of outgoing stack slots killed above the out_preserve_stack_slots - // for calls to C. Supports the var-args backing area for register parms. - // ADLC doesn't support parsing expressions, so I folded the math by hand. - // (callee_register_argument_save_area_words (6) + callee_aggregate_return_pointer_words (0)) * 2-stack-slots-per-word - varargs_C_out_slots_killed(12); - - // The after-PROLOG location of the return address. Location of - // return address specifies a type (REG or STACK) and a number - // representing the register number (i.e. - use a register name) or - // stack slot. - return_addr(REG R_I7); // Ret Addr is in register I7 - - // Body of function which returns an OptoRegs array locating - // arguments either in registers or in stack slots for calling - // java - calling_convention %{ - (void) SharedRuntime::java_calling_convention(sig_bt, regs, length, is_outgoing); - - %} - - // Body of function which returns an OptoRegs array locating - // arguments either in registers or in stack slots for calling - // C. - c_calling_convention %{ - // This is obviously always outgoing - (void) SharedRuntime::c_calling_convention(sig_bt, regs, /*regs2=*/NULL, length); - %} - - // Location of native (C/C++) and interpreter return values. This is specified to - // be the same as Java. In the 32-bit VM, long values are actually returned from - // native calls in O0:O1 and returned to the interpreter in I0:I1. The copying - // to and from the register pairs is done by the appropriate call and epilog - // opcodes. This simplifies the register allocator. - c_return_value %{ - assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" ); - static int lo_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_O0_num, R_O0_num, R_O0_num, R_F0_num, R_F0_num, R_O0_num }; - static int hi_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_O0H_num, OptoReg::Bad, R_F1_num, R_O0H_num}; - static int lo_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_I0_num, R_I0_num, R_I0_num, R_F0_num, R_F0_num, R_I0_num }; - static int hi_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_I0H_num, OptoReg::Bad, R_F1_num, R_I0H_num}; - return OptoRegPair( (is_outgoing?hi_out:hi_in)[ideal_reg], - (is_outgoing?lo_out:lo_in)[ideal_reg] ); - %} - - // Location of compiled Java return values. Same as C - return_value %{ - assert( ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, "only return normal values" ); - static int lo_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_O0_num, R_O0_num, R_O0_num, R_F0_num, R_F0_num, R_O0_num }; - static int hi_out[Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_O0H_num, OptoReg::Bad, R_F1_num, R_O0H_num}; - static int lo_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, R_I0_num, R_I0_num, R_I0_num, R_F0_num, R_F0_num, R_I0_num }; - static int hi_in [Op_RegL+1] = { OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, OptoReg::Bad, R_I0H_num, OptoReg::Bad, R_F1_num, R_I0H_num}; - return OptoRegPair( (is_outgoing?hi_out:hi_in)[ideal_reg], - (is_outgoing?lo_out:lo_in)[ideal_reg] ); - %} - -%} - - -//----------ATTRIBUTES--------------------------------------------------------- -//----------Operand Attributes------------------------------------------------- -op_attrib op_cost(1); // Required cost attribute - -//----------Instruction Attributes--------------------------------------------- -ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute -ins_attrib ins_size(32); // Required size attribute (in bits) - -// avoid_back_to_back attribute is an expression that must return -// one of the following values defined in MachNode: -// AVOID_NONE - instruction can be placed anywhere -// AVOID_BEFORE - instruction cannot be placed after an -// instruction with MachNode::AVOID_AFTER -// AVOID_AFTER - the next instruction cannot be the one -// with MachNode::AVOID_BEFORE -// AVOID_BEFORE_AND_AFTER - BEFORE and AFTER attributes at -// the same time -ins_attrib ins_avoid_back_to_back(MachNode::AVOID_NONE); - -ins_attrib ins_short_branch(0); // Required flag: is this instruction a - // non-matching short branch variant of some - // long branch? - -//----------OPERANDS----------------------------------------------------------- -// Operand definitions must precede instruction definitions for correct parsing -// in the ADLC because operands constitute user defined types which are used in -// instruction definitions. - -//----------Simple Operands---------------------------------------------------- -// Immediate Operands -// Integer Immediate: 32-bit -operand immI() %{ - match(ConI); - - op_cost(0); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 0-bit -operand immI0() %{ - predicate(n->get_int() == 0); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 5-bit -operand immI5() %{ - predicate(Assembler::is_simm5(n->get_int())); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 8-bit -operand immI8() %{ - predicate(Assembler::is_simm8(n->get_int())); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the value 10 -operand immI10() %{ - predicate(n->get_int() == 10); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 11-bit -operand immI11() %{ - predicate(Assembler::is_simm11(n->get_int())); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 13-bit -operand immI13() %{ - predicate(Assembler::is_simm13(n->get_int())); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 13-bit minus 7 -operand immI13m7() %{ - predicate((-4096 < n->get_int()) && ((n->get_int() + 7) <= 4095)); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 16-bit -operand immI16() %{ - predicate(Assembler::is_simm16(n->get_int())); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the values 1-31 -operand immI_1_31() %{ - predicate(n->get_int() >= 1 && n->get_int() <= 31); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the values 32-63 -operand immI_32_63() %{ - predicate(n->get_int() >= 32 && n->get_int() <= 63); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Immediates for special shifts (sign extend) - -// Integer Immediate: the value 16 -operand immI_16() %{ - predicate(n->get_int() == 16); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the value 24 -operand immI_24() %{ - predicate(n->get_int() == 24); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} -// Integer Immediate: the value 255 -operand immI_255() %{ - predicate( n->get_int() == 255 ); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the value 65535 -operand immI_65535() %{ - predicate(n->get_int() == 65535); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: the values 0-31 -operand immU5() %{ - predicate(n->get_int() >= 0 && n->get_int() <= 31); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 6-bit -operand immU6() %{ - predicate(n->get_int() >= 0 && n->get_int() <= 63); - match(ConI); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Unsigned Integer Immediate: 12-bit (non-negative that fits in simm13) -operand immU12() %{ - predicate((0 <= n->get_int()) && Assembler::is_simm13(n->get_int())); - match(ConI); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Unsigned Long Immediate: 12-bit (non-negative that fits in simm13) -operand immUL12() %{ - predicate((0 <= n->get_long()) && (n->get_long() == (int)n->get_long()) && Assembler::is_simm13((int)n->get_long())); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate non-negative -operand immU31() -%{ - predicate(n->get_int() >= 0); - match(ConI); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: the value FF -operand immL_FF() %{ - predicate( n->get_long() == 0xFFL ); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: the value FFFF -operand immL_FFFF() %{ - predicate( n->get_long() == 0xFFFFL ); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Pointer Immediate: 32 or 64-bit -operand immP() %{ - match(ConP); - - op_cost(5); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -// Pointer Immediate: 64-bit -operand immP_set() %{ - predicate(!VM_Version::has_fast_ld()); - match(ConP); - - op_cost(5); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -// Pointer Immediate: 64-bit -// From Niagara2 processors on a load should be better than materializing. -operand immP_load() %{ - predicate(VM_Version::has_fast_ld() && (n->bottom_type()->isa_oop_ptr() || (MacroAssembler::insts_for_set(n->get_ptr()) > 3))); - match(ConP); - - op_cost(5); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -// Pointer Immediate: 64-bit -operand immP_no_oop_cheap() %{ - predicate(VM_Version::has_fast_ld() && !n->bottom_type()->isa_oop_ptr() && (MacroAssembler::insts_for_set(n->get_ptr()) <= 3)); - match(ConP); - - op_cost(5); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -operand immP13() %{ - predicate((-4096 < n->get_ptr()) && (n->get_ptr() <= 4095)); - match(ConP); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -operand immP0() %{ - predicate(n->get_ptr() == 0); - match(ConP); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Pointer Immediate -operand immN() -%{ - match(ConN); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -operand immNKlass() -%{ - match(ConNKlass); - - op_cost(10); - format %{ %} - interface(CONST_INTER); -%} - -// NULL Pointer Immediate -operand immN0() -%{ - predicate(n->get_narrowcon() == 0); - match(ConN); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -operand immL() %{ - match(ConL); - op_cost(40); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -operand immL0() %{ - predicate(n->get_long() == 0L); - match(ConL); - op_cost(0); - // formats are generated automatically for constants and base registers - format %{ %} - interface(CONST_INTER); -%} - -// Integer Immediate: 5-bit -operand immL5() %{ - predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm5((int)n->get_long())); - match(ConL); - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: 13-bit -operand immL13() %{ - predicate((-4096L < n->get_long()) && (n->get_long() <= 4095L)); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: 13-bit minus 7 -operand immL13m7() %{ - predicate((-4096L < n->get_long()) && ((n->get_long() + 7L) <= 4095L)); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: low 32-bit mask -operand immL_32bits() %{ - predicate(n->get_long() == 0xFFFFFFFFL); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: cheap (materialize in <= 3 instructions) -operand immL_cheap() %{ - predicate(!VM_Version::has_fast_ld() || MacroAssembler::insts_for_set64(n->get_long()) <= 3); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Long Immediate: expensive (materialize in > 3 instructions) -operand immL_expensive() %{ - predicate(VM_Version::has_fast_ld() && MacroAssembler::insts_for_set64(n->get_long()) > 3); - match(ConL); - op_cost(0); - - format %{ %} - interface(CONST_INTER); -%} - -// Double Immediate -operand immD() %{ - match(ConD); - - op_cost(40); - format %{ %} - interface(CONST_INTER); -%} - -// Double Immediate: +0.0d -operand immD0() %{ - predicate(jlong_cast(n->getd()) == 0); - match(ConD); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Float Immediate -operand immF() %{ - match(ConF); - - op_cost(20); - format %{ %} - interface(CONST_INTER); -%} - -// Float Immediate: +0.0f -operand immF0() %{ - predicate(jint_cast(n->getf()) == 0); - match(ConF); - - op_cost(0); - format %{ %} - interface(CONST_INTER); -%} - -// Integer Register Operands -// Integer Register -operand iRegI() %{ - constraint(ALLOC_IN_RC(int_reg)); - match(RegI); - - match(notemp_iRegI); - match(g1RegI); - match(o0RegI); - match(iRegIsafe); - - format %{ %} - interface(REG_INTER); -%} - -operand notemp_iRegI() %{ - constraint(ALLOC_IN_RC(notemp_int_reg)); - match(RegI); - - match(o0RegI); - - format %{ %} - interface(REG_INTER); -%} - -operand o0RegI() %{ - constraint(ALLOC_IN_RC(o0_regI)); - match(iRegI); - - format %{ %} - interface(REG_INTER); -%} - -// Pointer Register -operand iRegP() %{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(RegP); - - match(lock_ptr_RegP); - match(g1RegP); - match(g2RegP); - match(g3RegP); - match(g4RegP); - match(i0RegP); - match(o0RegP); - match(o1RegP); - match(l7RegP); - - format %{ %} - interface(REG_INTER); -%} - -operand sp_ptr_RegP() %{ - constraint(ALLOC_IN_RC(sp_ptr_reg)); - match(RegP); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand lock_ptr_RegP() %{ - constraint(ALLOC_IN_RC(lock_ptr_reg)); - match(RegP); - match(i0RegP); - match(o0RegP); - match(o1RegP); - match(l7RegP); - - format %{ %} - interface(REG_INTER); -%} - -operand g1RegP() %{ - constraint(ALLOC_IN_RC(g1_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand g2RegP() %{ - constraint(ALLOC_IN_RC(g2_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand g3RegP() %{ - constraint(ALLOC_IN_RC(g3_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand g1RegI() %{ - constraint(ALLOC_IN_RC(g1_regI)); - match(iRegI); - - format %{ %} - interface(REG_INTER); -%} - -operand g3RegI() %{ - constraint(ALLOC_IN_RC(g3_regI)); - match(iRegI); - - format %{ %} - interface(REG_INTER); -%} - -operand g4RegI() %{ - constraint(ALLOC_IN_RC(g4_regI)); - match(iRegI); - - format %{ %} - interface(REG_INTER); -%} - -operand g4RegP() %{ - constraint(ALLOC_IN_RC(g4_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand i0RegP() %{ - constraint(ALLOC_IN_RC(i0_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand o0RegP() %{ - constraint(ALLOC_IN_RC(o0_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand o1RegP() %{ - constraint(ALLOC_IN_RC(o1_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand o2RegP() %{ - constraint(ALLOC_IN_RC(o2_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand o7RegP() %{ - constraint(ALLOC_IN_RC(o7_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand l7RegP() %{ - constraint(ALLOC_IN_RC(l7_regP)); - match(iRegP); - - format %{ %} - interface(REG_INTER); -%} - -operand o7RegI() %{ - constraint(ALLOC_IN_RC(o7_regI)); - match(iRegI); - - format %{ %} - interface(REG_INTER); -%} - -operand iRegN() %{ - constraint(ALLOC_IN_RC(int_reg)); - match(RegN); - - format %{ %} - interface(REG_INTER); -%} - -// Long Register -operand iRegL() %{ - constraint(ALLOC_IN_RC(long_reg)); - match(RegL); - - format %{ %} - interface(REG_INTER); -%} - -operand o2RegL() %{ - constraint(ALLOC_IN_RC(o2_regL)); - match(iRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand o7RegL() %{ - constraint(ALLOC_IN_RC(o7_regL)); - match(iRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand g1RegL() %{ - constraint(ALLOC_IN_RC(g1_regL)); - match(iRegL); - - format %{ %} - interface(REG_INTER); -%} - -operand g3RegL() %{ - constraint(ALLOC_IN_RC(g3_regL)); - match(iRegL); - - format %{ %} - interface(REG_INTER); -%} - -// Int Register safe -// This is 64bit safe -operand iRegIsafe() %{ - constraint(ALLOC_IN_RC(long_reg)); - - match(iRegI); - - format %{ %} - interface(REG_INTER); -%} - -// Condition Code Flag Register -operand flagsReg() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "ccr" %} // both ICC and XCC - interface(REG_INTER); -%} - -// Condition Code Register, unsigned comparisons. -operand flagsRegU() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "icc_U" %} - interface(REG_INTER); -%} - -// Condition Code Register, pointer comparisons. -operand flagsRegP() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "xcc_P" %} - interface(REG_INTER); -%} - -// Condition Code Register, long comparisons. -operand flagsRegL() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "xcc_L" %} - interface(REG_INTER); -%} - -// Condition Code Register, unsigned long comparisons. -operand flagsRegUL() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - - format %{ "xcc_UL" %} - interface(REG_INTER); -%} - -// Condition Code Register, floating comparisons, unordered same as "less". -operand flagsRegF() %{ - constraint(ALLOC_IN_RC(float_flags)); - match(RegFlags); - match(flagsRegF0); - - format %{ %} - interface(REG_INTER); -%} - -operand flagsRegF0() %{ - constraint(ALLOC_IN_RC(float_flag0)); - match(RegFlags); - - format %{ %} - interface(REG_INTER); -%} - - -// Condition Code Flag Register used by long compare -operand flagsReg_long_LTGE() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - format %{ "icc_LTGE" %} - interface(REG_INTER); -%} -operand flagsReg_long_EQNE() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - format %{ "icc_EQNE" %} - interface(REG_INTER); -%} -operand flagsReg_long_LEGT() %{ - constraint(ALLOC_IN_RC(int_flags)); - match(RegFlags); - format %{ "icc_LEGT" %} - interface(REG_INTER); -%} - - -operand regD() %{ - constraint(ALLOC_IN_RC(dflt_reg)); - match(RegD); - - match(regD_low); - - format %{ %} - interface(REG_INTER); -%} - -operand regF() %{ - constraint(ALLOC_IN_RC(sflt_reg)); - match(RegF); - - format %{ %} - interface(REG_INTER); -%} - -operand regD_low() %{ - constraint(ALLOC_IN_RC(dflt_low_reg)); - match(regD); - - format %{ %} - interface(REG_INTER); -%} - -// Special Registers - -// Method Register -operand inline_cache_regP(iRegP reg) %{ - constraint(ALLOC_IN_RC(g5_regP)); // G5=inline_cache_reg but uses 2 bits instead of 1 - match(reg); - format %{ %} - interface(REG_INTER); -%} - -operand interpreter_method_oop_regP(iRegP reg) %{ - constraint(ALLOC_IN_RC(g5_regP)); // G5=interpreter_method_oop_reg but uses 2 bits instead of 1 - match(reg); - format %{ %} - interface(REG_INTER); -%} - - -//----------Complex Operands--------------------------------------------------- -// Indirect Memory Reference -operand indirect(sp_ptr_RegP reg) %{ - constraint(ALLOC_IN_RC(sp_ptr_reg)); - match(reg); - - op_cost(100); - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x0); - scale(0x0); - disp(0x0); - %} -%} - -// Indirect with simm13 Offset -operand indOffset13(sp_ptr_RegP reg, immX13 offset) %{ - constraint(ALLOC_IN_RC(sp_ptr_reg)); - match(AddP reg offset); - - op_cost(100); - format %{ "[$reg + $offset]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x0); - scale(0x0); - disp($offset); - %} -%} - -// Indirect with simm13 Offset minus 7 -operand indOffset13m7(sp_ptr_RegP reg, immX13m7 offset) %{ - constraint(ALLOC_IN_RC(sp_ptr_reg)); - match(AddP reg offset); - - op_cost(100); - format %{ "[$reg + $offset]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x0); - scale(0x0); - disp($offset); - %} -%} - -// Note: Intel has a swapped version also, like this: -//operand indOffsetX(iRegI reg, immP offset) %{ -// constraint(ALLOC_IN_RC(int_reg)); -// match(AddP offset reg); -// -// op_cost(100); -// format %{ "[$reg + $offset]" %} -// interface(MEMORY_INTER) %{ -// base($reg); -// index(0x0); -// scale(0x0); -// disp($offset); -// %} -//%} -//// However, it doesn't make sense for SPARC, since -// we have no particularly good way to embed oops in -// single instructions. - -// Indirect with Register Index -operand indIndex(iRegP addr, iRegX index) %{ - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP addr index); - - op_cost(100); - format %{ "[$addr + $index]" %} - interface(MEMORY_INTER) %{ - base($addr); - index($index); - scale(0x0); - disp(0x0); - %} -%} - -//----------Special Memory Operands-------------------------------------------- -// Stack Slot Operand - This operand is used for loading and storing temporary -// values on the stack where a match requires a value to -// flow through memory. -operand stackSlotI(sRegI reg) %{ - constraint(ALLOC_IN_RC(stack_slots)); - op_cost(100); - //match(RegI); - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0xE); // R_SP - index(0x0); - scale(0x0); - disp($reg); // Stack Offset - %} -%} - -operand stackSlotP(sRegP reg) %{ - constraint(ALLOC_IN_RC(stack_slots)); - op_cost(100); - //match(RegP); - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0xE); // R_SP - index(0x0); - scale(0x0); - disp($reg); // Stack Offset - %} -%} - -operand stackSlotF(sRegF reg) %{ - constraint(ALLOC_IN_RC(stack_slots)); - op_cost(100); - //match(RegF); - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0xE); // R_SP - index(0x0); - scale(0x0); - disp($reg); // Stack Offset - %} -%} -operand stackSlotD(sRegD reg) %{ - constraint(ALLOC_IN_RC(stack_slots)); - op_cost(100); - //match(RegD); - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0xE); // R_SP - index(0x0); - scale(0x0); - disp($reg); // Stack Offset - %} -%} -operand stackSlotL(sRegL reg) %{ - constraint(ALLOC_IN_RC(stack_slots)); - op_cost(100); - //match(RegL); - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base(0xE); // R_SP - index(0x0); - scale(0x0); - disp($reg); // Stack Offset - %} -%} - -// Operands for expressing Control Flow -// NOTE: Label is a predefined operand which should not be redefined in -// the AD file. It is generically handled within the ADLC. - -//----------Conditional Branch Operands---------------------------------------- -// Comparison Op - This is the operation of the comparison, and is limited to -// the following set of codes: -// L (<), LE (<=), G (>), GE (>=), E (==), NE (!=) -// -// Other attributes of the comparison, such as unsignedness, are specified -// by the comparison instruction that sets a condition code flags register. -// That result is represented by a flags operand whose subtype is appropriate -// to the unsignedness (etc.) of the comparison. -// -// Later, the instruction which matches both the Comparison Op (a Bool) and -// the flags (produced by the Cmp) specifies the coding of the comparison op -// by matching a specific subtype of Bool operand below, such as cmpOpU. - -operand cmpOp() %{ - match(Bool); - - format %{ "" %} - interface(COND_INTER) %{ - equal(0x1); - not_equal(0x9); - less(0x3); - greater_equal(0xB); - less_equal(0x2); - greater(0xA); - overflow(0x7); - no_overflow(0xF); - %} -%} - -// Comparison Op, unsigned -operand cmpOpU() %{ - match(Bool); - predicate(n->as_Bool()->_test._test != BoolTest::overflow && - n->as_Bool()->_test._test != BoolTest::no_overflow); - - format %{ "u" %} - interface(COND_INTER) %{ - equal(0x1); - not_equal(0x9); - less(0x5); - greater_equal(0xD); - less_equal(0x4); - greater(0xC); - overflow(0x7); - no_overflow(0xF); - %} -%} - -// Comparison Op, pointer (same as unsigned) -operand cmpOpP() %{ - match(Bool); - predicate(n->as_Bool()->_test._test != BoolTest::overflow && - n->as_Bool()->_test._test != BoolTest::no_overflow); - - format %{ "p" %} - interface(COND_INTER) %{ - equal(0x1); - not_equal(0x9); - less(0x5); - greater_equal(0xD); - less_equal(0x4); - greater(0xC); - overflow(0x7); - no_overflow(0xF); - %} -%} - -// Comparison Op, branch-register encoding -operand cmpOp_reg() %{ - match(Bool); - predicate(n->as_Bool()->_test._test != BoolTest::overflow && - n->as_Bool()->_test._test != BoolTest::no_overflow); - - format %{ "" %} - interface(COND_INTER) %{ - equal (0x1); - not_equal (0x5); - less (0x3); - greater_equal(0x7); - less_equal (0x2); - greater (0x6); - overflow(0x7); // not supported - no_overflow(0xF); // not supported - %} -%} - -// Comparison Code, floating, unordered same as less -operand cmpOpF() %{ - match(Bool); - predicate(n->as_Bool()->_test._test != BoolTest::overflow && - n->as_Bool()->_test._test != BoolTest::no_overflow); - - format %{ "fl" %} - interface(COND_INTER) %{ - equal(0x9); - not_equal(0x1); - less(0x3); - greater_equal(0xB); - less_equal(0xE); - greater(0x6); - - overflow(0x7); // not supported - no_overflow(0xF); // not supported - %} -%} - -// Used by long compare -operand cmpOp_commute() %{ - match(Bool); - predicate(n->as_Bool()->_test._test != BoolTest::overflow && - n->as_Bool()->_test._test != BoolTest::no_overflow); - - format %{ "" %} - interface(COND_INTER) %{ - equal(0x1); - not_equal(0x9); - less(0xA); - greater_equal(0x2); - less_equal(0xB); - greater(0x3); - overflow(0x7); - no_overflow(0xF); - %} -%} - -//----------OPERAND CLASSES---------------------------------------------------- -// Operand Classes are groups of operands that are used to simplify -// instruction definitions by not requiring the AD writer to specify separate -// instructions for every form of operand when the instruction accepts -// multiple operand types with the same basic encoding and format. The classic -// case of this is memory operands. -opclass memory( indirect, indOffset13, indIndex ); -opclass indIndexMemory( indIndex ); - -//----------PIPELINE----------------------------------------------------------- -pipeline %{ - -//----------ATTRIBUTES--------------------------------------------------------- -attributes %{ - fixed_size_instructions; // Fixed size instructions - branch_has_delay_slot; // Branch has delay slot following - max_instructions_per_bundle = 4; // Up to 4 instructions per bundle - instruction_unit_size = 4; // An instruction is 4 bytes long - instruction_fetch_unit_size = 16; // The processor fetches one line - instruction_fetch_units = 1; // of 16 bytes - - // List of nop instructions - nops( Nop_A0, Nop_A1, Nop_MS, Nop_FA, Nop_BR ); -%} - -//----------RESOURCES---------------------------------------------------------- -// Resources are the functional units available to the machine -resources(A0, A1, MS, BR, FA, FM, IDIV, FDIV, IALU = A0 | A1); - -//----------PIPELINE DESCRIPTION----------------------------------------------- -// Pipeline Description specifies the stages in the machine's pipeline - -pipe_desc(A, P, F, B, I, J, S, R, E, C, M, W, X, T, D); - -//----------PIPELINE CLASSES--------------------------------------------------- -// Pipeline Classes describe the stages in which input and output are -// referenced by the hardware pipeline. - -// Integer ALU reg-reg operation -pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - single_instruction; - dst : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; -%} - -// Integer ALU reg-reg long operation -pipe_class ialu_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{ - instruction_count(2); - dst : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; - IALU : R; -%} - -// Integer ALU reg-reg long dependent operation -pipe_class ialu_reg_reg_2_dep(iRegL dst, iRegL src1, iRegL src2, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : E(write); - src1 : R(read); - src2 : R(read); - cr : E(write); - IALU : R(2); -%} - -// Integer ALU reg-imm operaion -pipe_class ialu_reg_imm(iRegI dst, iRegI src1, immI13 src2) %{ - single_instruction; - dst : E(write); - src1 : R(read); - IALU : R; -%} - -// Integer ALU reg-reg operation with condition code -pipe_class ialu_cc_reg_reg(iRegI dst, iRegI src1, iRegI src2, flagsReg cr) %{ - single_instruction; - dst : E(write); - cr : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; -%} - -// Integer ALU reg-imm operation with condition code -pipe_class ialu_cc_reg_imm(iRegI dst, iRegI src1, immI13 src2, flagsReg cr) %{ - single_instruction; - dst : E(write); - cr : E(write); - src1 : R(read); - IALU : R; -%} - -// Integer ALU zero-reg operation -pipe_class ialu_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{ - single_instruction; - dst : E(write); - src2 : R(read); - IALU : R; -%} - -// Integer ALU zero-reg operation with condition code only -pipe_class ialu_cconly_zero_reg(flagsReg cr, iRegI src) %{ - single_instruction; - cr : E(write); - src : R(read); - IALU : R; -%} - -// Integer ALU reg-reg operation with condition code only -pipe_class ialu_cconly_reg_reg(flagsReg cr, iRegI src1, iRegI src2) %{ - single_instruction; - cr : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; -%} - -// Integer ALU reg-imm operation with condition code only -pipe_class ialu_cconly_reg_imm(flagsReg cr, iRegI src1, immI13 src2) %{ - single_instruction; - cr : E(write); - src1 : R(read); - IALU : R; -%} - -// Integer ALU reg-reg-zero operation with condition code only -pipe_class ialu_cconly_reg_reg_zero(flagsReg cr, iRegI src1, iRegI src2, immI0 zero) %{ - single_instruction; - cr : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; -%} - -// Integer ALU reg-imm-zero operation with condition code only -pipe_class ialu_cconly_reg_imm_zero(flagsReg cr, iRegI src1, immI13 src2, immI0 zero) %{ - single_instruction; - cr : E(write); - src1 : R(read); - IALU : R; -%} - -// Integer ALU reg-reg operation with condition code, src1 modified -pipe_class ialu_cc_rwreg_reg(flagsReg cr, iRegI src1, iRegI src2) %{ - single_instruction; - cr : E(write); - src1 : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; -%} - -// Integer ALU reg-imm operation with condition code, src1 modified -pipe_class ialu_cc_rwreg_imm(flagsReg cr, iRegI src1, immI13 src2) %{ - single_instruction; - cr : E(write); - src1 : E(write); - src1 : R(read); - IALU : R; -%} - -pipe_class cmpL_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg cr ) %{ - multiple_bundles; - dst : E(write)+4; - cr : E(write); - src1 : R(read); - src2 : R(read); - IALU : R(3); - BR : R(2); -%} - -// Integer ALU operation -pipe_class ialu_none(iRegI dst) %{ - single_instruction; - dst : E(write); - IALU : R; -%} - -// Integer ALU reg operation -pipe_class ialu_reg(iRegI dst, iRegI src) %{ - single_instruction; may_have_no_code; - dst : E(write); - src : R(read); - IALU : R; -%} - -// Integer ALU reg conditional operation -// This instruction has a 1 cycle stall, and cannot execute -// in the same cycle as the instruction setting the condition -// code. We kludge this by pretending to read the condition code -// 1 cycle earlier, and by marking the functional units as busy -// for 2 cycles with the result available 1 cycle later than -// is really the case. -pipe_class ialu_reg_flags( iRegI op2_out, iRegI op2_in, iRegI op1, flagsReg cr ) %{ - single_instruction; - op2_out : C(write); - op1 : R(read); - cr : R(read); // This is really E, with a 1 cycle stall - BR : R(2); - MS : R(2); -%} - -pipe_class ialu_clr_and_mover( iRegI dst, iRegP src ) %{ - instruction_count(1); multiple_bundles; - dst : C(write)+1; - src : R(read)+1; - IALU : R(1); - BR : E(2); - MS : E(2); -%} - -// Integer ALU reg operation -pipe_class ialu_move_reg_L_to_I(iRegI dst, iRegL src) %{ - single_instruction; may_have_no_code; - dst : E(write); - src : R(read); - IALU : R; -%} -pipe_class ialu_move_reg_I_to_L(iRegL dst, iRegI src) %{ - single_instruction; may_have_no_code; - dst : E(write); - src : R(read); - IALU : R; -%} - -// Two integer ALU reg operations -pipe_class ialu_reg_2(iRegL dst, iRegL src) %{ - instruction_count(2); - dst : E(write); - src : R(read); - A0 : R; - A1 : R; -%} - -// Two integer ALU reg operations -pipe_class ialu_move_reg_L_to_L(iRegL dst, iRegL src) %{ - instruction_count(2); may_have_no_code; - dst : E(write); - src : R(read); - A0 : R; - A1 : R; -%} - -// Integer ALU imm operation -pipe_class ialu_imm(iRegI dst, immI13 src) %{ - single_instruction; - dst : E(write); - IALU : R; -%} - -// Integer ALU reg-reg with carry operation -pipe_class ialu_reg_reg_cy(iRegI dst, iRegI src1, iRegI src2, iRegI cy) %{ - single_instruction; - dst : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; -%} - -// Integer ALU cc operation -pipe_class ialu_cc(iRegI dst, flagsReg cc) %{ - single_instruction; - dst : E(write); - cc : R(read); - IALU : R; -%} - -// Integer ALU cc / second IALU operation -pipe_class ialu_reg_ialu( iRegI dst, iRegI src ) %{ - instruction_count(1); multiple_bundles; - dst : E(write)+1; - src : R(read); - IALU : R; -%} - -// Integer ALU cc / second IALU operation -pipe_class ialu_reg_reg_ialu( iRegI dst, iRegI p, iRegI q ) %{ - instruction_count(1); multiple_bundles; - dst : E(write)+1; - p : R(read); - q : R(read); - IALU : R; -%} - -// Integer ALU hi-lo-reg operation -pipe_class ialu_hi_lo_reg(iRegI dst, immI src) %{ - instruction_count(1); multiple_bundles; - dst : E(write)+1; - IALU : R(2); -%} - -// Float ALU hi-lo-reg operation (with temp) -pipe_class ialu_hi_lo_reg_temp(regF dst, immF src, g3RegP tmp) %{ - instruction_count(1); multiple_bundles; - dst : E(write)+1; - IALU : R(2); -%} - -// Long Constant -pipe_class loadConL( iRegL dst, immL src ) %{ - instruction_count(2); multiple_bundles; - dst : E(write)+1; - IALU : R(2); - IALU : R(2); -%} - -// Pointer Constant -pipe_class loadConP( iRegP dst, immP src ) %{ - instruction_count(0); multiple_bundles; - fixed_latency(6); -%} - -// Long Constant small -pipe_class loadConLlo( iRegL dst, immL src ) %{ - instruction_count(2); - dst : E(write); - IALU : R; - IALU : R; -%} - -// [PHH] This is wrong for 64-bit. See LdImmF/D. -pipe_class loadConFD(regF dst, immF src, g3RegP tmp) %{ - instruction_count(1); multiple_bundles; - src : R(read); - dst : M(write)+1; - IALU : R; - MS : E; -%} - -// Integer ALU nop operation -pipe_class ialu_nop() %{ - single_instruction; - IALU : R; -%} - -// Integer ALU nop operation -pipe_class ialu_nop_A0() %{ - single_instruction; - A0 : R; -%} - -// Integer ALU nop operation -pipe_class ialu_nop_A1() %{ - single_instruction; - A1 : R; -%} - -// Integer Multiply reg-reg operation -pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - single_instruction; - dst : E(write); - src1 : R(read); - src2 : R(read); - MS : R(5); -%} - -// Integer Multiply reg-imm operation -pipe_class imul_reg_imm(iRegI dst, iRegI src1, immI13 src2) %{ - single_instruction; - dst : E(write); - src1 : R(read); - MS : R(5); -%} - -pipe_class mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - single_instruction; - dst : E(write)+4; - src1 : R(read); - src2 : R(read); - MS : R(6); -%} - -pipe_class mulL_reg_imm(iRegL dst, iRegL src1, immL13 src2) %{ - single_instruction; - dst : E(write)+4; - src1 : R(read); - MS : R(6); -%} - -// Integer Divide reg-reg -pipe_class sdiv_reg_reg(iRegI dst, iRegI src1, iRegI src2, iRegI temp, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : E(write); - temp : E(write); - src1 : R(read); - src2 : R(read); - temp : R(read); - MS : R(38); -%} - -// Integer Divide reg-imm -pipe_class sdiv_reg_imm(iRegI dst, iRegI src1, immI13 src2, iRegI temp, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : E(write); - temp : E(write); - src1 : R(read); - temp : R(read); - MS : R(38); -%} - -// Long Divide -pipe_class divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - dst : E(write)+71; - src1 : R(read); - src2 : R(read)+1; - MS : R(70); -%} - -pipe_class divL_reg_imm(iRegL dst, iRegL src1, immL13 src2) %{ - dst : E(write)+71; - src1 : R(read); - MS : R(70); -%} - -// Floating Point Add Float -pipe_class faddF_reg_reg(regF dst, regF src1, regF src2) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - FA : R; -%} - -// Floating Point Add Double -pipe_class faddD_reg_reg(regD dst, regD src1, regD src2) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - FA : R; -%} - -// Floating Point Conditional Move based on integer flags -pipe_class int_conditional_float_move (cmpOp cmp, flagsReg cr, regF dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - cr : R(read); - FA : R(2); - BR : R(2); -%} - -// Floating Point Conditional Move based on integer flags -pipe_class int_conditional_double_move (cmpOp cmp, flagsReg cr, regD dst, regD src) %{ - single_instruction; - dst : X(write); - src : E(read); - cr : R(read); - FA : R(2); - BR : R(2); -%} - -// Floating Point Multiply Float -pipe_class fmulF_reg_reg(regF dst, regF src1, regF src2) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - FM : R; -%} - -// Floating Point Multiply Double -pipe_class fmulD_reg_reg(regD dst, regD src1, regD src2) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - FM : R; -%} - -// Floating Point Divide Float -pipe_class fdivF_reg_reg(regF dst, regF src1, regF src2) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - FM : R; - FDIV : C(14); -%} - -// Floating Point Divide Double -pipe_class fdivD_reg_reg(regD dst, regD src1, regD src2) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - FM : R; - FDIV : C(17); -%} - -// Fused floating-point multiply-add float. -pipe_class fmaF_regx4(regF dst, regF src1, regF src2, regF src3) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - src3 : E(read); - FM : R; -%} - -// Fused gloating-point multiply-add double. -pipe_class fmaD_regx4(regD dst, regD src1, regD src2, regD src3) %{ - single_instruction; - dst : X(write); - src1 : E(read); - src2 : E(read); - src3 : E(read); - FM : R; -%} - -// Floating Point Move/Negate/Abs Float -pipe_class faddF_reg(regF dst, regF src) %{ - single_instruction; - dst : W(write); - src : E(read); - FA : R(1); -%} - -// Floating Point Move/Negate/Abs Double -pipe_class faddD_reg(regD dst, regD src) %{ - single_instruction; - dst : W(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert F->D -pipe_class fcvtF2D(regD dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert I->D -pipe_class fcvtI2D(regD dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert LHi->D -pipe_class fcvtLHi2D(regD dst, regD src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert L->D -pipe_class fcvtL2D(regD dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert L->F -pipe_class fcvtL2F(regD dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert D->F -pipe_class fcvtD2F(regD dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert I->L -pipe_class fcvtI2L(regD dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Convert D->F -pipe_class fcvtD2I(regF dst, regD src, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : X(write)+6; - src : E(read); - FA : R; -%} - -// Floating Point Convert D->L -pipe_class fcvtD2L(regD dst, regD src, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : X(write)+6; - src : E(read); - FA : R; -%} - -// Floating Point Convert F->I -pipe_class fcvtF2I(regF dst, regF src, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : X(write)+6; - src : E(read); - FA : R; -%} - -// Floating Point Convert F->L -pipe_class fcvtF2L(regD dst, regF src, flagsReg cr) %{ - instruction_count(1); multiple_bundles; - dst : X(write)+6; - src : E(read); - FA : R; -%} - -// Floating Point Convert I->F -pipe_class fcvtI2F(regF dst, regF src) %{ - single_instruction; - dst : X(write); - src : E(read); - FA : R; -%} - -// Floating Point Compare -pipe_class faddF_fcc_reg_reg_zero(flagsRegF cr, regF src1, regF src2, immI0 zero) %{ - single_instruction; - cr : X(write); - src1 : E(read); - src2 : E(read); - FA : R; -%} - -// Floating Point Compare -pipe_class faddD_fcc_reg_reg_zero(flagsRegF cr, regD src1, regD src2, immI0 zero) %{ - single_instruction; - cr : X(write); - src1 : E(read); - src2 : E(read); - FA : R; -%} - -// Floating Add Nop -pipe_class fadd_nop() %{ - single_instruction; - FA : R; -%} - -// Integer Store to Memory -pipe_class istore_mem_reg(memory mem, iRegI src) %{ - single_instruction; - mem : R(read); - src : C(read); - MS : R; -%} - -// Integer Store to Memory -pipe_class istore_mem_spORreg(memory mem, sp_ptr_RegP src) %{ - single_instruction; - mem : R(read); - src : C(read); - MS : R; -%} - -// Integer Store Zero to Memory -pipe_class istore_mem_zero(memory mem, immI0 src) %{ - single_instruction; - mem : R(read); - MS : R; -%} - -// Special Stack Slot Store -pipe_class istore_stk_reg(stackSlotI stkSlot, iRegI src) %{ - single_instruction; - stkSlot : R(read); - src : C(read); - MS : R; -%} - -// Special Stack Slot Store -pipe_class lstoreI_stk_reg(stackSlotL stkSlot, iRegI src) %{ - instruction_count(2); multiple_bundles; - stkSlot : R(read); - src : C(read); - MS : R(2); -%} - -// Float Store -pipe_class fstoreF_mem_reg(memory mem, RegF src) %{ - single_instruction; - mem : R(read); - src : C(read); - MS : R; -%} - -// Float Store -pipe_class fstoreF_mem_zero(memory mem, immF0 src) %{ - single_instruction; - mem : R(read); - MS : R; -%} - -// Double Store -pipe_class fstoreD_mem_reg(memory mem, RegD src) %{ - instruction_count(1); - mem : R(read); - src : C(read); - MS : R; -%} - -// Double Store -pipe_class fstoreD_mem_zero(memory mem, immD0 src) %{ - single_instruction; - mem : R(read); - MS : R; -%} - -// Special Stack Slot Float Store -pipe_class fstoreF_stk_reg(stackSlotI stkSlot, RegF src) %{ - single_instruction; - stkSlot : R(read); - src : C(read); - MS : R; -%} - -// Special Stack Slot Double Store -pipe_class fstoreD_stk_reg(stackSlotI stkSlot, RegD src) %{ - single_instruction; - stkSlot : R(read); - src : C(read); - MS : R; -%} - -// Integer Load (when sign bit propagation not needed) -pipe_class iload_mem(iRegI dst, memory mem) %{ - single_instruction; - mem : R(read); - dst : C(write); - MS : R; -%} - -// Integer Load from stack operand -pipe_class iload_stkD(iRegI dst, stackSlotD mem ) %{ - single_instruction; - mem : R(read); - dst : C(write); - MS : R; -%} - -// Integer Load (when sign bit propagation or masking is needed) -pipe_class iload_mask_mem(iRegI dst, memory mem) %{ - single_instruction; - mem : R(read); - dst : M(write); - MS : R; -%} - -// Float Load -pipe_class floadF_mem(regF dst, memory mem) %{ - single_instruction; - mem : R(read); - dst : M(write); - MS : R; -%} - -// Float Load -pipe_class floadD_mem(regD dst, memory mem) %{ - instruction_count(1); multiple_bundles; // Again, unaligned argument is only multiple case - mem : R(read); - dst : M(write); - MS : R; -%} - -// Float Load -pipe_class floadF_stk(regF dst, stackSlotI stkSlot) %{ - single_instruction; - stkSlot : R(read); - dst : M(write); - MS : R; -%} - -// Float Load -pipe_class floadD_stk(regD dst, stackSlotI stkSlot) %{ - single_instruction; - stkSlot : R(read); - dst : M(write); - MS : R; -%} - -// Memory Nop -pipe_class mem_nop() %{ - single_instruction; - MS : R; -%} - -pipe_class sethi(iRegP dst, immI src) %{ - single_instruction; - dst : E(write); - IALU : R; -%} - -pipe_class loadPollP(iRegP poll) %{ - single_instruction; - poll : R(read); - MS : R; -%} - -pipe_class br(Universe br, label labl) %{ - single_instruction_with_delay_slot; - BR : R; -%} - -pipe_class br_cc(Universe br, cmpOp cmp, flagsReg cr, label labl) %{ - single_instruction_with_delay_slot; - cr : E(read); - BR : R; -%} - -pipe_class br_reg(Universe br, cmpOp cmp, iRegI op1, label labl) %{ - single_instruction_with_delay_slot; - op1 : E(read); - BR : R; - MS : R; -%} - -// Compare and branch -pipe_class cmp_br_reg_reg(Universe br, cmpOp cmp, iRegI src1, iRegI src2, label labl, flagsReg cr) %{ - instruction_count(2); has_delay_slot; - cr : E(write); - src1 : R(read); - src2 : R(read); - IALU : R; - BR : R; -%} - -// Compare and branch -pipe_class cmp_br_reg_imm(Universe br, cmpOp cmp, iRegI src1, immI13 src2, label labl, flagsReg cr) %{ - instruction_count(2); has_delay_slot; - cr : E(write); - src1 : R(read); - IALU : R; - BR : R; -%} - -// Compare and branch using cbcond -pipe_class cbcond_reg_reg(Universe br, cmpOp cmp, iRegI src1, iRegI src2, label labl) %{ - single_instruction; - src1 : E(read); - src2 : E(read); - IALU : R; - BR : R; -%} - -// Compare and branch using cbcond -pipe_class cbcond_reg_imm(Universe br, cmpOp cmp, iRegI src1, immI5 src2, label labl) %{ - single_instruction; - src1 : E(read); - IALU : R; - BR : R; -%} - -pipe_class br_fcc(Universe br, cmpOpF cc, flagsReg cr, label labl) %{ - single_instruction_with_delay_slot; - cr : E(read); - BR : R; -%} - -pipe_class br_nop() %{ - single_instruction; - BR : R; -%} - -pipe_class simple_call(method meth) %{ - instruction_count(2); multiple_bundles; force_serialization; - fixed_latency(100); - BR : R(1); - MS : R(1); - A0 : R(1); -%} - -pipe_class compiled_call(method meth) %{ - instruction_count(1); multiple_bundles; force_serialization; - fixed_latency(100); - MS : R(1); -%} - -pipe_class call(method meth) %{ - instruction_count(0); multiple_bundles; force_serialization; - fixed_latency(100); -%} - -pipe_class tail_call(Universe ignore, label labl) %{ - single_instruction; has_delay_slot; - fixed_latency(100); - BR : R(1); - MS : R(1); -%} - -pipe_class ret(Universe ignore) %{ - single_instruction; has_delay_slot; - BR : R(1); - MS : R(1); -%} - -pipe_class ret_poll(g3RegP poll) %{ - instruction_count(3); has_delay_slot; - poll : E(read); - MS : R; -%} - -// The real do-nothing guy -pipe_class empty( ) %{ - instruction_count(0); -%} - -pipe_class long_memory_op() %{ - instruction_count(0); multiple_bundles; force_serialization; - fixed_latency(25); - MS : R(1); -%} - -// Check-cast -pipe_class partial_subtype_check_pipe(Universe ignore, iRegP array, iRegP match ) %{ - array : R(read); - match : R(read); - IALU : R(2); - BR : R(2); - MS : R; -%} - -// Convert FPU flags into +1,0,-1 -pipe_class floating_cmp( iRegI dst, regF src1, regF src2 ) %{ - src1 : E(read); - src2 : E(read); - dst : E(write); - FA : R; - MS : R(2); - BR : R(2); -%} - -// Compare for p < q, and conditionally add y -pipe_class cadd_cmpltmask( iRegI p, iRegI q, iRegI y ) %{ - p : E(read); - q : E(read); - y : E(read); - IALU : R(3) -%} - -// Perform a compare, then move conditionally in a branch delay slot. -pipe_class min_max( iRegI src2, iRegI srcdst ) %{ - src2 : E(read); - srcdst : E(read); - IALU : R; - BR : R; -%} - -// Define the class for the Nop node -define %{ - MachNop = ialu_nop; -%} - -%} - -//----------INSTRUCTIONS------------------------------------------------------- - -//------------Special Stack Slot instructions - no match rules----------------- -instruct stkI_to_regF(regF dst, stackSlotI src) %{ - // No match rule to avoid chain rule match. - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - format %{ "LDF $src,$dst\t! stkI to regF" %} - opcode(Assembler::ldf_op3); - ins_encode(simple_form3_mem_reg(src, dst)); - ins_pipe(floadF_stk); -%} - -instruct stkL_to_regD(regD dst, stackSlotL src) %{ - // No match rule to avoid chain rule match. - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - format %{ "LDDF $src,$dst\t! stkL to regD" %} - opcode(Assembler::lddf_op3); - ins_encode(simple_form3_mem_reg(src, dst)); - ins_pipe(floadD_stk); -%} - -instruct regF_to_stkI(stackSlotI dst, regF src) %{ - // No match rule to avoid chain rule match. - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - format %{ "STF $src,$dst\t! regF to stkI" %} - opcode(Assembler::stf_op3); - ins_encode(simple_form3_mem_reg(dst, src)); - ins_pipe(fstoreF_stk_reg); -%} - -instruct regD_to_stkL(stackSlotL dst, regD src) %{ - // No match rule to avoid chain rule match. - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - format %{ "STDF $src,$dst\t! regD to stkL" %} - opcode(Assembler::stdf_op3); - ins_encode(simple_form3_mem_reg(dst, src)); - ins_pipe(fstoreD_stk_reg); -%} - -instruct regI_to_stkLHi(stackSlotL dst, iRegI src) %{ - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST*2); - format %{ "STW $src,$dst.hi\t! long\n\t" - "STW R_G0,$dst.lo" %} - opcode(Assembler::stw_op3); - ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, R_G0)); - ins_pipe(lstoreI_stk_reg); -%} - -instruct regL_to_stkD(stackSlotD dst, iRegL src) %{ - // No match rule to avoid chain rule match. - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - format %{ "STX $src,$dst\t! regL to stkD" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( dst, src ) ); - ins_pipe(istore_stk_reg); -%} - -//---------- Chain stack slots between similar types -------- - -// Load integer from stack slot -instruct stkI_to_regI( iRegI dst, stackSlotI src ) %{ - match(Set dst src); - ins_cost(MEMORY_REF_COST); - - format %{ "LDUW $src,$dst\t!stk" %} - opcode(Assembler::lduw_op3); - ins_encode(simple_form3_mem_reg( src, dst ) ); - ins_pipe(iload_mem); -%} - -// Store integer to stack slot -instruct regI_to_stkI( stackSlotI dst, iRegI src ) %{ - match(Set dst src); - ins_cost(MEMORY_REF_COST); - - format %{ "STW $src,$dst\t!stk" %} - opcode(Assembler::stw_op3); - ins_encode(simple_form3_mem_reg( dst, src ) ); - ins_pipe(istore_mem_reg); -%} - -// Load long from stack slot -instruct stkL_to_regL( iRegL dst, stackSlotL src ) %{ - match(Set dst src); - - ins_cost(MEMORY_REF_COST); - format %{ "LDX $src,$dst\t! long" %} - opcode(Assembler::ldx_op3); - ins_encode(simple_form3_mem_reg( src, dst ) ); - ins_pipe(iload_mem); -%} - -// Store long to stack slot -instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ - match(Set dst src); - - ins_cost(MEMORY_REF_COST); - format %{ "STX $src,$dst\t! long" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( dst, src ) ); - ins_pipe(istore_mem_reg); -%} - -// Load pointer from stack slot, 64-bit encoding -instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ - match(Set dst src); - ins_cost(MEMORY_REF_COST); - format %{ "LDX $src,$dst\t!ptr" %} - opcode(Assembler::ldx_op3); - ins_encode(simple_form3_mem_reg( src, dst ) ); - ins_pipe(iload_mem); -%} - -// Store pointer to stack slot -instruct regP_to_stkP(stackSlotP dst, iRegP src) %{ - match(Set dst src); - ins_cost(MEMORY_REF_COST); - format %{ "STX $src,$dst\t!ptr" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( dst, src ) ); - ins_pipe(istore_mem_reg); -%} - -//------------Special Nop instructions for bundling - no match rules----------- -// Nop using the A0 functional unit -instruct Nop_A0() %{ - ins_cost(0); - - format %{ "NOP ! Alu Pipeline" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form2_nop() ); - ins_pipe(ialu_nop_A0); -%} - -// Nop using the A1 functional unit -instruct Nop_A1( ) %{ - ins_cost(0); - - format %{ "NOP ! Alu Pipeline" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form2_nop() ); - ins_pipe(ialu_nop_A1); -%} - -// Nop using the memory functional unit -instruct Nop_MS( ) %{ - ins_cost(0); - - format %{ "NOP ! Memory Pipeline" %} - ins_encode( emit_mem_nop ); - ins_pipe(mem_nop); -%} - -// Nop using the floating add functional unit -instruct Nop_FA( ) %{ - ins_cost(0); - - format %{ "NOP ! Floating Add Pipeline" %} - ins_encode( emit_fadd_nop ); - ins_pipe(fadd_nop); -%} - -// Nop using the branch functional unit -instruct Nop_BR( ) %{ - ins_cost(0); - - format %{ "NOP ! Branch Pipeline" %} - ins_encode( emit_br_nop ); - ins_pipe(br_nop); -%} - -//----------Load/Store/Move Instructions--------------------------------------- -//----------Load Instructions-------------------------------------------------- -// Load Byte (8bit signed) -instruct loadB(iRegI dst, memory mem) %{ - match(Set dst (LoadB mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSB $mem,$dst\t! byte" %} - ins_encode %{ - __ ldsb($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Byte (8bit signed) into a Long Register -instruct loadB2L(iRegL dst, memory mem) %{ - match(Set dst (ConvI2L (LoadB mem))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSB $mem,$dst\t! byte -> long" %} - ins_encode %{ - __ ldsb($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Unsigned Byte (8bit UNsigned) into an int reg -instruct loadUB(iRegI dst, memory mem) %{ - match(Set dst (LoadUB mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUB $mem,$dst\t! ubyte" %} - ins_encode %{ - __ ldub($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Byte (8bit UNsigned) into a Long Register -instruct loadUB2L(iRegL dst, memory mem) %{ - match(Set dst (ConvI2L (LoadUB mem))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUB $mem,$dst\t! ubyte -> long" %} - ins_encode %{ - __ ldub($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Byte (8 bit UNsigned) with 32-bit mask into Long Register -instruct loadUB2L_immI(iRegL dst, memory mem, immI mask) %{ - match(Set dst (ConvI2L (AndI (LoadUB mem) mask))); - ins_cost(MEMORY_REF_COST + DEFAULT_COST); - - size(2*4); - format %{ "LDUB $mem,$dst\t# ubyte & 32-bit mask -> long\n\t" - "AND $dst,right_n_bits($mask, 8),$dst" %} - ins_encode %{ - __ ldub($mem$$Address, $dst$$Register); - __ and3($dst$$Register, $mask$$constant & right_n_bits(8), $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Short (16bit signed) -instruct loadS(iRegI dst, memory mem) %{ - match(Set dst (LoadS mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSH $mem,$dst\t! short" %} - ins_encode %{ - __ ldsh($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Short (16 bit signed) to Byte (8 bit signed) -instruct loadS2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{ - match(Set dst (RShiftI (LShiftI (LoadS mem) twentyfour) twentyfour)); - ins_cost(MEMORY_REF_COST); - - size(4); - - format %{ "LDSB $mem+1,$dst\t! short -> byte" %} - ins_encode %{ - __ ldsb($mem$$Address, $dst$$Register, 1); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Short (16bit signed) into a Long Register -instruct loadS2L(iRegL dst, memory mem) %{ - match(Set dst (ConvI2L (LoadS mem))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSH $mem,$dst\t! short -> long" %} - ins_encode %{ - __ ldsh($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Unsigned Short/Char (16bit UNsigned) -instruct loadUS(iRegI dst, memory mem) %{ - match(Set dst (LoadUS mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUH $mem,$dst\t! ushort/char" %} - ins_encode %{ - __ lduh($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Short/Char (16 bit UNsigned) to Byte (8 bit signed) -instruct loadUS2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{ - match(Set dst (RShiftI (LShiftI (LoadUS mem) twentyfour) twentyfour)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSB $mem+1,$dst\t! ushort -> byte" %} - ins_encode %{ - __ ldsb($mem$$Address, $dst$$Register, 1); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Unsigned Short/Char (16bit UNsigned) into a Long Register -instruct loadUS2L(iRegL dst, memory mem) %{ - match(Set dst (ConvI2L (LoadUS mem))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUH $mem,$dst\t! ushort/char -> long" %} - ins_encode %{ - __ lduh($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Short/Char (16bit UNsigned) with mask 0xFF into a Long Register -instruct loadUS2L_immI_255(iRegL dst, indOffset13m7 mem, immI_255 mask) %{ - match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUB $mem+1,$dst\t! ushort/char & 0xFF -> long" %} - ins_encode %{ - __ ldub($mem$$Address, $dst$$Register, 1); // LSB is index+1 on BE - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Short/Char (16bit UNsigned) with a 13-bit mask into a Long Register -instruct loadUS2L_immI13(iRegL dst, memory mem, immI13 mask) %{ - match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); - ins_cost(MEMORY_REF_COST + DEFAULT_COST); - - size(2*4); - format %{ "LDUH $mem,$dst\t! ushort/char & 13-bit mask -> long\n\t" - "AND $dst,$mask,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - __ lduh($mem$$Address, Rdst); - __ and3(Rdst, $mask$$constant, Rdst); - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Short/Char (16bit UNsigned) with a 32-bit mask into a Long Register -instruct loadUS2L_immI(iRegL dst, memory mem, immI mask, iRegL tmp) %{ - match(Set dst (ConvI2L (AndI (LoadUS mem) mask))); - effect(TEMP dst, TEMP tmp); - ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST); - - format %{ "LDUH $mem,$dst\t! ushort/char & 32-bit mask -> long\n\t" - "SET right_n_bits($mask, 16),$tmp\n\t" - "AND $dst,$tmp,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rtmp = $tmp$$Register; - __ lduh($mem$$Address, Rdst); - __ set($mask$$constant & right_n_bits(16), Rtmp); - __ and3(Rdst, Rtmp, Rdst); - %} - ins_pipe(iload_mem); -%} - -// Load Integer -instruct loadI(iRegI dst, memory mem) %{ - match(Set dst (LoadI mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUW $mem,$dst\t! int" %} - ins_encode %{ - __ lduw($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Integer to Byte (8 bit signed) -instruct loadI2B(iRegI dst, indOffset13m7 mem, immI_24 twentyfour) %{ - match(Set dst (RShiftI (LShiftI (LoadI mem) twentyfour) twentyfour)); - ins_cost(MEMORY_REF_COST); - - size(4); - - format %{ "LDSB $mem+3,$dst\t! int -> byte" %} - ins_encode %{ - __ ldsb($mem$$Address, $dst$$Register, 3); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Integer to Unsigned Byte (8 bit UNsigned) -instruct loadI2UB(iRegI dst, indOffset13m7 mem, immI_255 mask) %{ - match(Set dst (AndI (LoadI mem) mask)); - ins_cost(MEMORY_REF_COST); - - size(4); - - format %{ "LDUB $mem+3,$dst\t! int -> ubyte" %} - ins_encode %{ - __ ldub($mem$$Address, $dst$$Register, 3); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Integer to Short (16 bit signed) -instruct loadI2S(iRegI dst, indOffset13m7 mem, immI_16 sixteen) %{ - match(Set dst (RShiftI (LShiftI (LoadI mem) sixteen) sixteen)); - ins_cost(MEMORY_REF_COST); - - size(4); - - format %{ "LDSH $mem+2,$dst\t! int -> short" %} - ins_encode %{ - __ ldsh($mem$$Address, $dst$$Register, 2); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Integer to Unsigned Short (16 bit UNsigned) -instruct loadI2US(iRegI dst, indOffset13m7 mem, immI_65535 mask) %{ - match(Set dst (AndI (LoadI mem) mask)); - ins_cost(MEMORY_REF_COST); - - size(4); - - format %{ "LDUH $mem+2,$dst\t! int -> ushort/char" %} - ins_encode %{ - __ lduh($mem$$Address, $dst$$Register, 2); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Integer into a Long Register -instruct loadI2L(iRegL dst, memory mem) %{ - match(Set dst (ConvI2L (LoadI mem))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDSW $mem,$dst\t! int -> long" %} - ins_encode %{ - __ ldsw($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mask_mem); -%} - -// Load Integer with mask 0xFF into a Long Register -instruct loadI2L_immI_255(iRegL dst, indOffset13m7 mem, immI_255 mask) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUB $mem+3,$dst\t! int & 0xFF -> long" %} - ins_encode %{ - __ ldub($mem$$Address, $dst$$Register, 3); // LSB is index+3 on BE - %} - ins_pipe(iload_mem); -%} - -// Load Integer with mask 0xFFFF into a Long Register -instruct loadI2L_immI_65535(iRegL dst, indOffset13m7 mem, immI_65535 mask) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUH $mem+2,$dst\t! int & 0xFFFF -> long" %} - ins_encode %{ - __ lduh($mem$$Address, $dst$$Register, 2); // LSW is index+2 on BE - %} - ins_pipe(iload_mem); -%} - -// Load Integer with a 12-bit mask into a Long Register -instruct loadI2L_immU12(iRegL dst, memory mem, immU12 mask) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - ins_cost(MEMORY_REF_COST + DEFAULT_COST); - - size(2*4); - format %{ "LDUW $mem,$dst\t! int & 12-bit mask -> long\n\t" - "AND $dst,$mask,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - __ lduw($mem$$Address, Rdst); - __ and3(Rdst, $mask$$constant, Rdst); - %} - ins_pipe(iload_mem); -%} - -// Load Integer with a 31-bit mask into a Long Register -instruct loadI2L_immU31(iRegL dst, memory mem, immU31 mask, iRegL tmp) %{ - match(Set dst (ConvI2L (AndI (LoadI mem) mask))); - effect(TEMP dst, TEMP tmp); - ins_cost(MEMORY_REF_COST + 2*DEFAULT_COST); - - format %{ "LDUW $mem,$dst\t! int & 31-bit mask -> long\n\t" - "SET $mask,$tmp\n\t" - "AND $dst,$tmp,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rtmp = $tmp$$Register; - __ lduw($mem$$Address, Rdst); - __ set($mask$$constant, Rtmp); - __ and3(Rdst, Rtmp, Rdst); - %} - ins_pipe(iload_mem); -%} - -// Load Unsigned Integer into a Long Register -instruct loadUI2L(iRegL dst, memory mem, immL_32bits mask) %{ - match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDUW $mem,$dst\t! uint -> long" %} - ins_encode %{ - __ lduw($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Long - aligned -instruct loadL(iRegL dst, memory mem ) %{ - match(Set dst (LoadL mem)); - ins_cost(MEMORY_REF_COST); - - size(4); - format %{ "LDX $mem,$dst\t! long" %} - ins_encode %{ - __ ldx($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Long - UNaligned -instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{ - match(Set dst (LoadL_unaligned mem)); - effect(KILL tmp); - ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - format %{ "LDUW $mem+4,R_O7\t! misaligned long\n" - "\tLDUW $mem ,$dst\n" - "\tSLLX #32, $dst, $dst\n" - "\tOR $dst, R_O7, $dst" %} - opcode(Assembler::lduw_op3); - ins_encode(form3_mem_reg_long_unaligned_marshal( mem, dst )); - ins_pipe(iload_mem); -%} - -// Load Range -instruct loadRange(iRegI dst, memory mem) %{ - match(Set dst (LoadRange mem)); - ins_cost(MEMORY_REF_COST); - - format %{ "LDUW $mem,$dst\t! range" %} - opcode(Assembler::lduw_op3); - ins_encode(simple_form3_mem_reg( mem, dst ) ); - ins_pipe(iload_mem); -%} - -// Load Integer into %f register (for fitos/fitod) -instruct loadI_freg(regF dst, memory mem) %{ - match(Set dst (LoadI mem)); - ins_cost(MEMORY_REF_COST); - - format %{ "LDF $mem,$dst\t! for fitos/fitod" %} - opcode(Assembler::ldf_op3); - ins_encode(simple_form3_mem_reg( mem, dst ) ); - ins_pipe(floadF_mem); -%} - -// Load Pointer -instruct loadP(iRegP dst, memory mem) %{ - match(Set dst (LoadP mem)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "LDX $mem,$dst\t! ptr" %} - ins_encode %{ - __ ldx($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Compressed Pointer -instruct loadN(iRegN dst, memory mem) %{ - match(Set dst (LoadN mem)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "LDUW $mem,$dst\t! compressed ptr" %} - ins_encode %{ - __ lduw($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Klass Pointer -instruct loadKlass(iRegP dst, memory mem) %{ - match(Set dst (LoadKlass mem)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "LDX $mem,$dst\t! klass ptr" %} - ins_encode %{ - __ ldx($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load narrow Klass Pointer -instruct loadNKlass(iRegN dst, memory mem) %{ - match(Set dst (LoadNKlass mem)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "LDUW $mem,$dst\t! compressed klass ptr" %} - ins_encode %{ - __ lduw($mem$$Address, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Double -instruct loadD(regD dst, memory mem) %{ - match(Set dst (LoadD mem)); - ins_cost(MEMORY_REF_COST); - - format %{ "LDDF $mem,$dst" %} - opcode(Assembler::lddf_op3); - ins_encode(simple_form3_mem_reg( mem, dst ) ); - ins_pipe(floadD_mem); -%} - -// Load Double - UNaligned -instruct loadD_unaligned(regD_low dst, memory mem ) %{ - match(Set dst (LoadD_unaligned mem)); - ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - format %{ "LDF $mem ,$dst.hi\t! misaligned double\n" - "\tLDF $mem+4,$dst.lo\t!" %} - opcode(Assembler::ldf_op3); - ins_encode( form3_mem_reg_double_unaligned( mem, dst )); - ins_pipe(iload_mem); -%} - -// Load Float -instruct loadF(regF dst, memory mem) %{ - match(Set dst (LoadF mem)); - ins_cost(MEMORY_REF_COST); - - format %{ "LDF $mem,$dst" %} - opcode(Assembler::ldf_op3); - ins_encode(simple_form3_mem_reg( mem, dst ) ); - ins_pipe(floadF_mem); -%} - -// Load Constant -instruct loadConI( iRegI dst, immI src ) %{ - match(Set dst src); - ins_cost(DEFAULT_COST * 3/2); - format %{ "SET $src,$dst" %} - ins_encode( Set32(src, dst) ); - ins_pipe(ialu_hi_lo_reg); -%} - -instruct loadConI13( iRegI dst, immI13 src ) %{ - match(Set dst src); - - size(4); - format %{ "MOV $src,$dst" %} - ins_encode( Set13( src, dst ) ); - ins_pipe(ialu_imm); -%} - -instruct loadConP_set(iRegP dst, immP_set con) %{ - match(Set dst con); - ins_cost(DEFAULT_COST * 3/2); - format %{ "SET $con,$dst\t! ptr" %} - ins_encode %{ - relocInfo::relocType constant_reloc = _opnds[1]->constant_reloc(); - intptr_t val = $con$$constant; - if (constant_reloc == relocInfo::oop_type) { - __ set_oop_constant((jobject) val, $dst$$Register); - } else if (constant_reloc == relocInfo::metadata_type) { - __ set_metadata_constant((Metadata*)val, $dst$$Register); - } else { // non-oop pointers, e.g. card mark base, heap top - assert(constant_reloc == relocInfo::none, "unexpected reloc type"); - __ set(val, $dst$$Register); - } - %} - ins_pipe(loadConP); -%} - -instruct loadConP_load(iRegP dst, immP_load con) %{ - match(Set dst con); - ins_cost(MEMORY_REF_COST); - format %{ "LD [$constanttablebase + $constantoffset],$dst\t! load from constant table: ptr=$con" %} - ins_encode %{ - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $dst$$Register); - __ ld_ptr($constanttablebase, con_offset, $dst$$Register); - %} - ins_pipe(loadConP); -%} - -instruct loadConP_no_oop_cheap(iRegP dst, immP_no_oop_cheap con) %{ - match(Set dst con); - ins_cost(DEFAULT_COST * 3/2); - format %{ "SET $con,$dst\t! non-oop ptr" %} - ins_encode %{ - if (_opnds[1]->constant_reloc() == relocInfo::metadata_type) { - __ set_metadata_constant((Metadata*)$con$$constant, $dst$$Register); - } else { - __ set($con$$constant, $dst$$Register); - } - %} - ins_pipe(loadConP); -%} - -instruct loadConP0(iRegP dst, immP0 src) %{ - match(Set dst src); - - size(4); - format %{ "CLR $dst\t!ptr" %} - ins_encode %{ - __ clr($dst$$Register); - %} - ins_pipe(ialu_imm); -%} - -instruct loadConN0(iRegN dst, immN0 src) %{ - match(Set dst src); - - size(4); - format %{ "CLR $dst\t! compressed NULL ptr" %} - ins_encode %{ - __ clr($dst$$Register); - %} - ins_pipe(ialu_imm); -%} - -instruct loadConN(iRegN dst, immN src) %{ - match(Set dst src); - ins_cost(DEFAULT_COST * 3/2); - format %{ "SET $src,$dst\t! compressed ptr" %} - ins_encode %{ - Register dst = $dst$$Register; - __ set_narrow_oop((jobject)$src$$constant, dst); - %} - ins_pipe(ialu_hi_lo_reg); -%} - -instruct loadConNKlass(iRegN dst, immNKlass src) %{ - match(Set dst src); - ins_cost(DEFAULT_COST * 3/2); - format %{ "SET $src,$dst\t! compressed klass ptr" %} - ins_encode %{ - Register dst = $dst$$Register; - __ set_narrow_klass((Klass*)$src$$constant, dst); - %} - ins_pipe(ialu_hi_lo_reg); -%} - -// Materialize long value (predicated by immL_cheap). -instruct loadConL_set64(iRegL dst, immL_cheap con, o7RegL tmp) %{ - match(Set dst con); - effect(KILL tmp); - ins_cost(DEFAULT_COST * 3); - format %{ "SET64 $con,$dst KILL $tmp\t! cheap long" %} - ins_encode %{ - __ set64($con$$constant, $dst$$Register, $tmp$$Register); - %} - ins_pipe(loadConL); -%} - -// Load long value from constant table (predicated by immL_expensive). -instruct loadConL_ldx(iRegL dst, immL_expensive con) %{ - match(Set dst con); - ins_cost(MEMORY_REF_COST); - format %{ "LDX [$constanttablebase + $constantoffset],$dst\t! load from constant table: long=$con" %} - ins_encode %{ - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $dst$$Register); - __ ldx($constanttablebase, con_offset, $dst$$Register); - %} - ins_pipe(loadConL); -%} - -instruct loadConL0( iRegL dst, immL0 src ) %{ - match(Set dst src); - ins_cost(DEFAULT_COST); - size(4); - format %{ "CLR $dst\t! long" %} - ins_encode( Set13( src, dst ) ); - ins_pipe(ialu_imm); -%} - -instruct loadConL13( iRegL dst, immL13 src ) %{ - match(Set dst src); - ins_cost(DEFAULT_COST * 2); - - size(4); - format %{ "MOV $src,$dst\t! long" %} - ins_encode( Set13( src, dst ) ); - ins_pipe(ialu_imm); -%} - -instruct loadConF(regF dst, immF con, o7RegI tmp) %{ - match(Set dst con); - effect(KILL tmp); - format %{ "LDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: float=$con" %} - ins_encode %{ - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $tmp$$Register); - __ ldf(FloatRegisterImpl::S, $constanttablebase, con_offset, $dst$$FloatRegister); - %} - ins_pipe(loadConFD); -%} - -instruct loadConD(regD dst, immD con, o7RegI tmp) %{ - match(Set dst con); - effect(KILL tmp); - format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: double=$con" %} - ins_encode %{ - // XXX This is a quick fix for 6833573. - //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset($con), $dst$$FloatRegister); - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset($con), $tmp$$Register); - __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(loadConFD); -%} - -// Prefetch instructions for allocation. -// Must be safe to execute with invalid address (cannot fault). - -instruct prefetchAlloc( memory mem ) %{ - predicate(AllocatePrefetchInstr == 0); - match( PrefetchAllocation mem ); - ins_cost(MEMORY_REF_COST); - - format %{ "PREFETCH $mem,2\t! Prefetch allocation" %} - opcode(Assembler::prefetch_op3); - ins_encode( form3_mem_prefetch_write( mem ) ); - ins_pipe(iload_mem); -%} - -// Use BIS instruction to prefetch for allocation. -// Could fault, need space at the end of TLAB. -instruct prefetchAlloc_bis( iRegP dst ) %{ - predicate(AllocatePrefetchInstr == 1); - match( PrefetchAllocation dst ); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "STXA [$dst]\t! // Prefetch allocation using BIS" %} - ins_encode %{ - __ stxa(G0, $dst$$Register, G0, Assembler::ASI_ST_BLKINIT_PRIMARY); - %} - ins_pipe(istore_mem_reg); -%} - -// Next code is used for finding next cache line address to prefetch. -instruct cacheLineAdr( iRegP dst, iRegP src, immL13 mask ) %{ - match(Set dst (CastX2P (AndL (CastP2X src) mask))); - ins_cost(DEFAULT_COST); - size(4); - - format %{ "AND $src,$mask,$dst\t! next cache line address" %} - ins_encode %{ - __ and3($src$$Register, $mask$$constant, $dst$$Register); - %} - ins_pipe(ialu_reg_imm); -%} - -//----------Store Instructions------------------------------------------------- -// Store Byte -instruct storeB(memory mem, iRegI src) %{ - match(Set mem (StoreB mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STB $src,$mem\t! byte" %} - opcode(Assembler::stb_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(istore_mem_reg); -%} - -instruct storeB0(memory mem, immI0 src) %{ - match(Set mem (StoreB mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STB $src,$mem\t! byte" %} - opcode(Assembler::stb_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(istore_mem_zero); -%} - -instruct storeCM0(memory mem, immI0 src) %{ - match(Set mem (StoreCM mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STB $src,$mem\t! CMS card-mark byte 0" %} - opcode(Assembler::stb_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(istore_mem_zero); -%} - -// Store Char/Short -instruct storeC(memory mem, iRegI src) %{ - match(Set mem (StoreC mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STH $src,$mem\t! short" %} - opcode(Assembler::sth_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(istore_mem_reg); -%} - -instruct storeC0(memory mem, immI0 src) %{ - match(Set mem (StoreC mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STH $src,$mem\t! short" %} - opcode(Assembler::sth_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(istore_mem_zero); -%} - -// Store Integer -instruct storeI(memory mem, iRegI src) %{ - match(Set mem (StoreI mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STW $src,$mem" %} - opcode(Assembler::stw_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(istore_mem_reg); -%} - -// Store Long -instruct storeL(memory mem, iRegL src) %{ - match(Set mem (StoreL mem src)); - ins_cost(MEMORY_REF_COST); - format %{ "STX $src,$mem\t! long" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(istore_mem_reg); -%} - -instruct storeI0(memory mem, immI0 src) %{ - match(Set mem (StoreI mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STW $src,$mem" %} - opcode(Assembler::stw_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(istore_mem_zero); -%} - -instruct storeL0(memory mem, immL0 src) %{ - match(Set mem (StoreL mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STX $src,$mem" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(istore_mem_zero); -%} - -// Store Integer from float register (used after fstoi) -instruct storeI_Freg(memory mem, regF src) %{ - match(Set mem (StoreI mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STF $src,$mem\t! after fstoi/fdtoi" %} - opcode(Assembler::stf_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(fstoreF_mem_reg); -%} - -// Store Pointer -instruct storeP(memory dst, sp_ptr_RegP src) %{ - match(Set dst (StoreP dst src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STX $src,$dst\t! ptr" %} - opcode(Assembler::stx_op3, 0, REGP_OP); - ins_encode( form3_mem_reg( dst, src ) ); - ins_pipe(istore_mem_spORreg); -%} - -instruct storeP0(memory dst, immP0 src) %{ - match(Set dst (StoreP dst src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STX $src,$dst\t! ptr" %} - opcode(Assembler::stx_op3, 0, REGP_OP); - ins_encode( form3_mem_reg( dst, R_G0 ) ); - ins_pipe(istore_mem_zero); -%} - -// Store Compressed Pointer -instruct storeN(memory dst, iRegN src) %{ - match(Set dst (StoreN dst src)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "STW $src,$dst\t! compressed ptr" %} - ins_encode %{ - Register base = as_Register($dst$$base); - Register index = as_Register($dst$$index); - Register src = $src$$Register; - if (index != G0) { - __ stw(src, base, index); - } else { - __ stw(src, base, $dst$$disp); - } - %} - ins_pipe(istore_mem_spORreg); -%} - -instruct storeNKlass(memory dst, iRegN src) %{ - match(Set dst (StoreNKlass dst src)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "STW $src,$dst\t! compressed klass ptr" %} - ins_encode %{ - Register base = as_Register($dst$$base); - Register index = as_Register($dst$$index); - Register src = $src$$Register; - if (index != G0) { - __ stw(src, base, index); - } else { - __ stw(src, base, $dst$$disp); - } - %} - ins_pipe(istore_mem_spORreg); -%} - -instruct storeN0(memory dst, immN0 src) %{ - match(Set dst (StoreN dst src)); - ins_cost(MEMORY_REF_COST); - size(4); - - format %{ "STW $src,$dst\t! compressed ptr" %} - ins_encode %{ - Register base = as_Register($dst$$base); - Register index = as_Register($dst$$index); - if (index != G0) { - __ stw(0, base, index); - } else { - __ stw(0, base, $dst$$disp); - } - %} - ins_pipe(istore_mem_zero); -%} - -// Store Double -instruct storeD( memory mem, regD src) %{ - match(Set mem (StoreD mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STDF $src,$mem" %} - opcode(Assembler::stdf_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(fstoreD_mem_reg); -%} - -instruct storeD0( memory mem, immD0 src) %{ - match(Set mem (StoreD mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STX $src,$mem" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(fstoreD_mem_zero); -%} - -// Store Float -instruct storeF( memory mem, regF src) %{ - match(Set mem (StoreF mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STF $src,$mem" %} - opcode(Assembler::stf_op3); - ins_encode(simple_form3_mem_reg( mem, src ) ); - ins_pipe(fstoreF_mem_reg); -%} - -instruct storeF0( memory mem, immF0 src) %{ - match(Set mem (StoreF mem src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STW $src,$mem\t! storeF0" %} - opcode(Assembler::stw_op3); - ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); - ins_pipe(fstoreF_mem_zero); -%} - -// Convert oop pointer into compressed form -instruct encodeHeapOop(iRegN dst, iRegP src) %{ - predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); - match(Set dst (EncodeP src)); - format %{ "encode_heap_oop $src, $dst" %} - ins_encode %{ - __ encode_heap_oop($src$$Register, $dst$$Register); - %} - ins_avoid_back_to_back(CompressedOops::base() == NULL ? AVOID_NONE : AVOID_BEFORE); - ins_pipe(ialu_reg); -%} - -instruct encodeHeapOop_not_null(iRegN dst, iRegP src) %{ - predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); - match(Set dst (EncodeP src)); - format %{ "encode_heap_oop_not_null $src, $dst" %} - ins_encode %{ - __ encode_heap_oop_not_null($src$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct decodeHeapOop(iRegP dst, iRegN src) %{ - predicate(n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && - n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant); - match(Set dst (DecodeN src)); - format %{ "decode_heap_oop $src, $dst" %} - ins_encode %{ - __ decode_heap_oop($src$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{ - predicate(n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || - n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant); - match(Set dst (DecodeN src)); - format %{ "decode_heap_oop_not_null $src, $dst" %} - ins_encode %{ - __ decode_heap_oop_not_null($src$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct encodeKlass_not_null(iRegN dst, iRegP src) %{ - match(Set dst (EncodePKlass src)); - format %{ "encode_klass_not_null $src, $dst" %} - ins_encode %{ - __ encode_klass_not_null($src$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -instruct decodeKlass_not_null(iRegP dst, iRegN src) %{ - match(Set dst (DecodeNKlass src)); - format %{ "decode_klass_not_null $src, $dst" %} - ins_encode %{ - __ decode_klass_not_null($src$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -//----------MemBar Instructions----------------------------------------------- -// Memory barrier flavors - -instruct membar_acquire() %{ - match(MemBarAcquire); - match(LoadFence); - ins_cost(4*MEMORY_REF_COST); - - size(0); - format %{ "MEMBAR-acquire" %} - ins_encode( enc_membar_acquire ); - ins_pipe(long_memory_op); -%} - -instruct membar_acquire_lock() %{ - match(MemBarAcquireLock); - ins_cost(0); - - size(0); - format %{ "!MEMBAR-acquire (CAS in prior FastLock so empty encoding)" %} - ins_encode( ); - ins_pipe(empty); -%} - -instruct membar_release() %{ - match(MemBarRelease); - match(StoreFence); - ins_cost(4*MEMORY_REF_COST); - - size(0); - format %{ "MEMBAR-release" %} - ins_encode( enc_membar_release ); - ins_pipe(long_memory_op); -%} - -instruct membar_release_lock() %{ - match(MemBarReleaseLock); - ins_cost(0); - - size(0); - format %{ "!MEMBAR-release (CAS in succeeding FastUnlock so empty encoding)" %} - ins_encode( ); - ins_pipe(empty); -%} - -instruct membar_volatile() %{ - match(MemBarVolatile); - ins_cost(4*MEMORY_REF_COST); - - size(4); - format %{ "MEMBAR-volatile" %} - ins_encode( enc_membar_volatile ); - ins_pipe(long_memory_op); -%} - -instruct unnecessary_membar_volatile() %{ - match(MemBarVolatile); - predicate(Matcher::post_store_load_barrier(n)); - ins_cost(0); - - size(0); - format %{ "!MEMBAR-volatile (unnecessary so empty encoding)" %} - ins_encode( ); - ins_pipe(empty); -%} - -instruct membar_storestore() %{ - match(MemBarStoreStore); - ins_cost(0); - - size(0); - format %{ "!MEMBAR-storestore (empty encoding)" %} - ins_encode( ); - ins_pipe(empty); -%} - -//----------Register Move Instructions----------------------------------------- -instruct roundDouble_nop(regD dst) %{ - match(Set dst (RoundDouble dst)); - ins_cost(0); - // SPARC results are already "rounded" (i.e., normal-format IEEE) - ins_encode( ); - ins_pipe(empty); -%} - - -instruct roundFloat_nop(regF dst) %{ - match(Set dst (RoundFloat dst)); - ins_cost(0); - // SPARC results are already "rounded" (i.e., normal-format IEEE) - ins_encode( ); - ins_pipe(empty); -%} - - -// Cast Index to Pointer for unsafe natives -instruct castX2P(iRegX src, iRegP dst) %{ - match(Set dst (CastX2P src)); - - format %{ "MOV $src,$dst\t! IntX->Ptr" %} - ins_encode( form3_g0_rs2_rd_move( src, dst ) ); - ins_pipe(ialu_reg); -%} - -// Cast Pointer to Index for unsafe natives -instruct castP2X(iRegP src, iRegX dst) %{ - match(Set dst (CastP2X src)); - - format %{ "MOV $src,$dst\t! Ptr->IntX" %} - ins_encode( form3_g0_rs2_rd_move( src, dst ) ); - ins_pipe(ialu_reg); -%} - -instruct stfSSD(stackSlotD stkSlot, regD src) %{ - // %%%% TO DO: Tell the coalescer that this kind of node is a copy! - match(Set stkSlot src); // chain rule - ins_cost(MEMORY_REF_COST); - format %{ "STDF $src,$stkSlot\t!stk" %} - opcode(Assembler::stdf_op3); - ins_encode(simple_form3_mem_reg(stkSlot, src)); - ins_pipe(fstoreD_stk_reg); -%} - -instruct ldfSSD(regD dst, stackSlotD stkSlot) %{ - // %%%% TO DO: Tell the coalescer that this kind of node is a copy! - match(Set dst stkSlot); // chain rule - ins_cost(MEMORY_REF_COST); - format %{ "LDDF $stkSlot,$dst\t!stk" %} - opcode(Assembler::lddf_op3); - ins_encode(simple_form3_mem_reg(stkSlot, dst)); - ins_pipe(floadD_stk); -%} - -instruct stfSSF(stackSlotF stkSlot, regF src) %{ - // %%%% TO DO: Tell the coalescer that this kind of node is a copy! - match(Set stkSlot src); // chain rule - ins_cost(MEMORY_REF_COST); - format %{ "STF $src,$stkSlot\t!stk" %} - opcode(Assembler::stf_op3); - ins_encode(simple_form3_mem_reg(stkSlot, src)); - ins_pipe(fstoreF_stk_reg); -%} - -//----------Conditional Move--------------------------------------------------- -// Conditional move -instruct cmovIP_reg(cmpOpP cmp, flagsRegP pcc, iRegI dst, iRegI src) %{ - match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $pcc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovIP_imm(cmpOpP cmp, flagsRegP pcc, iRegI dst, immI11 src) %{ - match(Set dst (CMoveI (Binary cmp pcc) (Binary dst src))); - ins_cost(140); - format %{ "MOV$cmp $pcc,$src,$dst" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovII_reg(cmpOp cmp, flagsReg icc, iRegI dst, iRegI src) %{ - match(Set dst (CMoveI (Binary cmp icc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $icc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovII_imm(cmpOp cmp, flagsReg icc, iRegI dst, immI11 src) %{ - match(Set dst (CMoveI (Binary cmp icc) (Binary dst src))); - ins_cost(140); - size(4); - format %{ "MOV$cmp $icc,$src,$dst" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovIIu_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{ - match(Set dst (CMoveI (Binary cmp icc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $icc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovIIu_imm(cmpOpU cmp, flagsRegU icc, iRegI dst, immI11 src) %{ - match(Set dst (CMoveI (Binary cmp icc) (Binary dst src))); - ins_cost(140); - size(4); - format %{ "MOV$cmp $icc,$src,$dst" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovIF_reg(cmpOpF cmp, flagsRegF fcc, iRegI dst, iRegI src) %{ - match(Set dst (CMoveI (Binary cmp fcc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $fcc,$src,$dst" %} - ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) ); - ins_pipe(ialu_reg); -%} - -instruct cmovIF_imm(cmpOpF cmp, flagsRegF fcc, iRegI dst, immI11 src) %{ - match(Set dst (CMoveI (Binary cmp fcc) (Binary dst src))); - ins_cost(140); - size(4); - format %{ "MOV$cmp $fcc,$src,$dst" %} - ins_encode( enc_cmov_imm_f(cmp,dst,src, fcc) ); - ins_pipe(ialu_imm); -%} - -// Conditional move for RegN. Only cmov(reg,reg). -instruct cmovNP_reg(cmpOpP cmp, flagsRegP pcc, iRegN dst, iRegN src) %{ - match(Set dst (CMoveN (Binary cmp pcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $pcc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_reg); -%} - -// This instruction also works with CmpN so we don't need cmovNN_reg. -instruct cmovNI_reg(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src) %{ - match(Set dst (CMoveN (Binary cmp icc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $icc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - -// This instruction also works with CmpN so we don't need cmovNN_reg. -instruct cmovNIu_reg(cmpOpU cmp, flagsRegU icc, iRegN dst, iRegN src) %{ - match(Set dst (CMoveN (Binary cmp icc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $icc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovNF_reg(cmpOpF cmp, flagsRegF fcc, iRegN dst, iRegN src) %{ - match(Set dst (CMoveN (Binary cmp fcc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $fcc,$src,$dst" %} - ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) ); - ins_pipe(ialu_reg); -%} - -// Conditional move -instruct cmovPP_reg(cmpOpP cmp, flagsRegP pcc, iRegP dst, iRegP src) %{ - match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $pcc,$src,$dst\t! ptr" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovPP_imm(cmpOpP cmp, flagsRegP pcc, iRegP dst, immP0 src) %{ - match(Set dst (CMoveP (Binary cmp pcc) (Binary dst src))); - ins_cost(140); - format %{ "MOV$cmp $pcc,$src,$dst\t! ptr" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_imm); -%} - -// This instruction also works with CmpN so we don't need cmovPN_reg. -instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{ - match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovPIu_reg(cmpOpU cmp, flagsRegU icc, iRegP dst, iRegP src) %{ - match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{ - match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); - ins_cost(140); - - size(4); - format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovPIu_imm(cmpOpU cmp, flagsRegU icc, iRegP dst, immP0 src) %{ - match(Set dst (CMoveP (Binary cmp icc) (Binary dst src))); - ins_cost(140); - - size(4); - format %{ "MOV$cmp $icc,$src,$dst\t! ptr" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovPF_reg(cmpOpF cmp, flagsRegF fcc, iRegP dst, iRegP src) %{ - match(Set dst (CMoveP (Binary cmp fcc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "MOV$cmp $fcc,$src,$dst" %} - ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) ); - ins_pipe(ialu_imm); -%} - -instruct cmovPF_imm(cmpOpF cmp, flagsRegF fcc, iRegP dst, immP0 src) %{ - match(Set dst (CMoveP (Binary cmp fcc) (Binary dst src))); - ins_cost(140); - size(4); - format %{ "MOV$cmp $fcc,$src,$dst" %} - ins_encode( enc_cmov_imm_f(cmp,dst,src, fcc) ); - ins_pipe(ialu_imm); -%} - -// Conditional move -instruct cmovFP_reg(cmpOpP cmp, flagsRegP pcc, regF dst, regF src) %{ - match(Set dst (CMoveF (Binary cmp pcc) (Binary dst src))); - ins_cost(150); - opcode(0x101); - format %{ "FMOVD$cmp $pcc,$src,$dst" %} - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(int_conditional_float_move); -%} - -instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{ - match(Set dst (CMoveF (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "FMOVS$cmp $icc,$src,$dst" %} - opcode(0x101); - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(int_conditional_float_move); -%} - -instruct cmovFIu_reg(cmpOpU cmp, flagsRegU icc, regF dst, regF src) %{ - match(Set dst (CMoveF (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "FMOVS$cmp $icc,$src,$dst" %} - opcode(0x101); - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(int_conditional_float_move); -%} - -// Conditional move, -instruct cmovFF_reg(cmpOpF cmp, flagsRegF fcc, regF dst, regF src) %{ - match(Set dst (CMoveF (Binary cmp fcc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "FMOVF$cmp $fcc,$src,$dst" %} - opcode(0x1); - ins_encode( enc_cmovff_reg(cmp,fcc,dst,src) ); - ins_pipe(int_conditional_double_move); -%} - -// Conditional move -instruct cmovDP_reg(cmpOpP cmp, flagsRegP pcc, regD dst, regD src) %{ - match(Set dst (CMoveD (Binary cmp pcc) (Binary dst src))); - ins_cost(150); - size(4); - opcode(0x102); - format %{ "FMOVD$cmp $pcc,$src,$dst" %} - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(int_conditional_double_move); -%} - -instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{ - match(Set dst (CMoveD (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "FMOVD$cmp $icc,$src,$dst" %} - opcode(0x102); - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(int_conditional_double_move); -%} - -instruct cmovDIu_reg(cmpOpU cmp, flagsRegU icc, regD dst, regD src) %{ - match(Set dst (CMoveD (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "FMOVD$cmp $icc,$src,$dst" %} - opcode(0x102); - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(int_conditional_double_move); -%} - -// Conditional move, -instruct cmovDF_reg(cmpOpF cmp, flagsRegF fcc, regD dst, regD src) %{ - match(Set dst (CMoveD (Binary cmp fcc) (Binary dst src))); - ins_cost(150); - size(4); - format %{ "FMOVD$cmp $fcc,$src,$dst" %} - opcode(0x2); - ins_encode( enc_cmovff_reg(cmp,fcc,dst,src) ); - ins_pipe(int_conditional_double_move); -%} - -// Conditional move -instruct cmovLP_reg(cmpOpP cmp, flagsRegP pcc, iRegL dst, iRegL src) %{ - match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $pcc,$src,$dst\t! long" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovLP_imm(cmpOpP cmp, flagsRegP pcc, iRegL dst, immI11 src) %{ - match(Set dst (CMoveL (Binary cmp pcc) (Binary dst src))); - ins_cost(140); - format %{ "MOV$cmp $pcc,$src,$dst\t! long" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::ptr_cc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{ - match(Set dst (CMoveL (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "MOV$cmp $icc,$src,$dst\t! long" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - - -instruct cmovLIu_reg(cmpOpU cmp, flagsRegU icc, iRegL dst, iRegL src) %{ - match(Set dst (CMoveL (Binary cmp icc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "MOV$cmp $icc,$src,$dst\t! long" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::icc)) ); - ins_pipe(ialu_reg); -%} - - -instruct cmovLF_reg(cmpOpF cmp, flagsRegF fcc, iRegL dst, iRegL src) %{ - match(Set dst (CMoveL (Binary cmp fcc) (Binary dst src))); - ins_cost(150); - - size(4); - format %{ "MOV$cmp $fcc,$src,$dst\t! long" %} - ins_encode( enc_cmov_reg_f(cmp,dst,src, fcc) ); - ins_pipe(ialu_reg); -%} - - - -//----------OS and Locking Instructions---------------------------------------- - -// This name is KNOWN by the ADLC and cannot be changed. -// The ADLC forces a 'TypeRawPtr::BOTTOM' output type -// for this guy. -instruct tlsLoadP(g2RegP dst) %{ - match(Set dst (ThreadLocal)); - - size(0); - ins_cost(0); - format %{ "# TLS is in G2" %} - ins_encode( /*empty encoding*/ ); - ins_pipe(ialu_none); -%} - -instruct checkCastPP( iRegP dst ) %{ - match(Set dst (CheckCastPP dst)); - - size(0); - format %{ "# checkcastPP of $dst" %} - ins_encode( /*empty encoding*/ ); - ins_pipe(empty); -%} - - -instruct castPP( iRegP dst ) %{ - match(Set dst (CastPP dst)); - format %{ "# castPP of $dst" %} - ins_encode( /*empty encoding*/ ); - ins_pipe(empty); -%} - -instruct castII( iRegI dst ) %{ - match(Set dst (CastII dst)); - format %{ "# castII of $dst" %} - ins_encode( /*empty encoding*/ ); - ins_cost(0); - ins_pipe(empty); -%} - -//----------Arithmetic Instructions-------------------------------------------- -// Addition Instructions -// Register Addition -instruct addI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (AddI src1 src2)); - - size(4); - format %{ "ADD $src1,$src2,$dst" %} - ins_encode %{ - __ add($src1$$Register, $src2$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -// Immediate Addition -instruct addI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{ - match(Set dst (AddI src1 src2)); - - size(4); - format %{ "ADD $src1,$src2,$dst" %} - opcode(Assembler::add_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Pointer Register Addition -instruct addP_reg_reg(iRegP dst, iRegP src1, iRegX src2) %{ - match(Set dst (AddP src1 src2)); - - size(4); - format %{ "ADD $src1,$src2,$dst" %} - opcode(Assembler::add_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Pointer Immediate Addition -instruct addP_reg_imm13(iRegP dst, iRegP src1, immX13 src2) %{ - match(Set dst (AddP src1 src2)); - - size(4); - format %{ "ADD $src1,$src2,$dst" %} - opcode(Assembler::add_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Long Addition -instruct addL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (AddL src1 src2)); - - size(4); - format %{ "ADD $src1,$src2,$dst\t! long" %} - opcode(Assembler::add_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -instruct addL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{ - match(Set dst (AddL src1 con)); - - size(4); - format %{ "ADD $src1,$con,$dst" %} - opcode(Assembler::add_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, con, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -//----------Conditional_store-------------------------------------------------- -// Conditional-store of the updated heap-top. -// Used during allocation of the shared heap. -// Sets flags (EQ) on success. Implemented with a CASA on Sparc. - -// LoadP-locked. Same as a regular pointer load when used with a compare-swap -instruct loadPLocked(iRegP dst, memory mem) %{ - match(Set dst (LoadPLocked mem)); - ins_cost(MEMORY_REF_COST); - - format %{ "LDX $mem,$dst\t! ptr" %} - opcode(Assembler::ldx_op3, 0, REGP_OP); - ins_encode( form3_mem_reg( mem, dst ) ); - ins_pipe(iload_mem); -%} - -instruct storePConditional( iRegP heap_top_ptr, iRegP oldval, g3RegP newval, flagsRegP pcc ) %{ - match(Set pcc (StorePConditional heap_top_ptr (Binary oldval newval))); - effect( KILL newval ); - format %{ "CASA [$heap_top_ptr],$oldval,R_G3\t! If $oldval==[$heap_top_ptr] Then store R_G3 into [$heap_top_ptr], set R_G3=[$heap_top_ptr] in any case\n\t" - "CMP R_G3,$oldval\t\t! See if we made progress" %} - ins_encode( enc_cas(heap_top_ptr,oldval,newval) ); - ins_pipe( long_memory_op ); -%} - -// Conditional-store of an int value. -instruct storeIConditional( iRegP mem_ptr, iRegI oldval, g3RegI newval, flagsReg icc ) %{ - match(Set icc (StoreIConditional mem_ptr (Binary oldval newval))); - effect( KILL newval ); - format %{ "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr], set $newval=[$mem_ptr] in any case\n\t" - "CMP $oldval,$newval\t\t! See if we made progress" %} - ins_encode( enc_cas(mem_ptr,oldval,newval) ); - ins_pipe( long_memory_op ); -%} - -// Conditional-store of a long value. -instruct storeLConditional( iRegP mem_ptr, iRegL oldval, g3RegL newval, flagsRegL xcc ) %{ - match(Set xcc (StoreLConditional mem_ptr (Binary oldval newval))); - effect( KILL newval ); - format %{ "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr], set $newval=[$mem_ptr] in any case\n\t" - "CMP $oldval,$newval\t\t! See if we made progress" %} - ins_encode( enc_cas(mem_ptr,oldval,newval) ); - ins_pipe( long_memory_op ); -%} - -// No flag versions for CompareAndSwap{P,I,L} because matcher can't match them - -instruct compareAndSwapL_bool(iRegP mem_ptr, iRegL oldval, iRegL newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{ - predicate(VM_Version::supports_cx8()); - match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); - effect( USE mem_ptr, KILL ccr, KILL tmp1); - format %{ - "MOV $newval,O7\n\t" - "CASXA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t" - "CMP $oldval,O7\t\t! See if we made progress\n\t" - "MOV 1,$res\n\t" - "MOVne xcc,R_G0,$res" - %} - ins_encode( enc_casx(mem_ptr, oldval, newval), - enc_lflags_ne_to_boolean(res) ); - ins_pipe( long_memory_op ); -%} - - -instruct compareAndSwapI_bool(iRegP mem_ptr, iRegI oldval, iRegI newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{ - match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); - effect( USE mem_ptr, KILL ccr, KILL tmp1); - format %{ - "MOV $newval,O7\n\t" - "CASA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t" - "CMP $oldval,O7\t\t! See if we made progress\n\t" - "MOV 1,$res\n\t" - "MOVne icc,R_G0,$res" - %} - ins_encode( enc_casi(mem_ptr, oldval, newval), - enc_iflags_ne_to_boolean(res) ); - ins_pipe( long_memory_op ); -%} - -instruct compareAndSwapP_bool(iRegP mem_ptr, iRegP oldval, iRegP newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{ - predicate(VM_Version::supports_cx8()); - match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); - effect( USE mem_ptr, KILL ccr, KILL tmp1); - format %{ - "MOV $newval,O7\n\t" - "CASA_PTR [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t" - "CMP $oldval,O7\t\t! See if we made progress\n\t" - "MOV 1,$res\n\t" - "MOVne xcc,R_G0,$res" - %} - ins_encode( enc_casx(mem_ptr, oldval, newval), - enc_lflags_ne_to_boolean(res) ); - ins_pipe( long_memory_op ); -%} - -instruct compareAndSwapN_bool(iRegP mem_ptr, iRegN oldval, iRegN newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{ - match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); - match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); - effect( USE mem_ptr, KILL ccr, KILL tmp1); - format %{ - "MOV $newval,O7\n\t" - "CASA [$mem_ptr],$oldval,O7\t! If $oldval==[$mem_ptr] Then store O7 into [$mem_ptr], set O7=[$mem_ptr] in any case\n\t" - "CMP $oldval,O7\t\t! See if we made progress\n\t" - "MOV 1,$res\n\t" - "MOVne icc,R_G0,$res" - %} - ins_encode( enc_casi(mem_ptr, oldval, newval), - enc_iflags_ne_to_boolean(res) ); - ins_pipe( long_memory_op ); -%} - -instruct compareAndExchangeI(iRegP mem_ptr, iRegI oldval, iRegI newval) -%{ - match(Set newval (CompareAndExchangeI mem_ptr (Binary oldval newval))); - effect( USE mem_ptr ); - - format %{ - "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t" - %} - ins_encode( enc_casi_exch(mem_ptr, oldval, newval) ); - ins_pipe( long_memory_op ); -%} - -instruct compareAndExchangeL(iRegP mem_ptr, iRegL oldval, iRegL newval) -%{ - match(Set newval (CompareAndExchangeL mem_ptr (Binary oldval newval))); - effect( USE mem_ptr ); - - format %{ - "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t" - %} - ins_encode( enc_casx_exch(mem_ptr, oldval, newval) ); - ins_pipe( long_memory_op ); -%} - -instruct compareAndExchangeP(iRegP mem_ptr, iRegP oldval, iRegP newval) -%{ - match(Set newval (CompareAndExchangeP mem_ptr (Binary oldval newval))); - effect( USE mem_ptr ); - - format %{ - "CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t" - %} - ins_encode( enc_casx_exch(mem_ptr, oldval, newval) ); - ins_pipe( long_memory_op ); -%} - -instruct compareAndExchangeN(iRegP mem_ptr, iRegN oldval, iRegN newval) -%{ - match(Set newval (CompareAndExchangeN mem_ptr (Binary oldval newval))); - effect( USE mem_ptr ); - - format %{ - "CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t" - %} - ins_encode( enc_casi_exch(mem_ptr, oldval, newval) ); - ins_pipe( long_memory_op ); -%} - -instruct xchgI( memory mem, iRegI newval) %{ - match(Set newval (GetAndSetI mem newval)); - format %{ "SWAP [$mem],$newval" %} - size(4); - ins_encode %{ - __ swap($mem$$Address, $newval$$Register); - %} - ins_pipe( long_memory_op ); -%} - - -instruct xchgN( memory mem, iRegN newval) %{ - match(Set newval (GetAndSetN mem newval)); - format %{ "SWAP [$mem],$newval" %} - size(4); - ins_encode %{ - __ swap($mem$$Address, $newval$$Register); - %} - ins_pipe( long_memory_op ); -%} - -//--------------------- -// Subtraction Instructions -// Register Subtraction -instruct subI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (SubI src1 src2)); - - size(4); - format %{ "SUB $src1,$src2,$dst" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Immediate Subtraction -instruct subI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{ - match(Set dst (SubI src1 src2)); - - size(4); - format %{ "SUB $src1,$src2,$dst" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -instruct subI_zero_reg(iRegI dst, immI0 zero, iRegI src2) %{ - match(Set dst (SubI zero src2)); - - size(4); - format %{ "NEG $src2,$dst" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( R_G0, src2, dst ) ); - ins_pipe(ialu_zero_reg); -%} - -// Long subtraction -instruct subL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (SubL src1 src2)); - - size(4); - format %{ "SUB $src1,$src2,$dst\t! long" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Immediate Subtraction -instruct subL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{ - match(Set dst (SubL src1 con)); - - size(4); - format %{ "SUB $src1,$con,$dst\t! long" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, con, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Long negation -instruct negL_reg_reg(iRegL dst, immL0 zero, iRegL src2) %{ - match(Set dst (SubL zero src2)); - - size(4); - format %{ "NEG $src2,$dst\t! long" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( R_G0, src2, dst ) ); - ins_pipe(ialu_zero_reg); -%} - -// Multiplication Instructions -// Integer Multiplication -// Register Multiplication -instruct mulI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (MulI src1 src2)); - - size(4); - format %{ "MULX $src1,$src2,$dst" %} - opcode(Assembler::mulx_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(imul_reg_reg); -%} - -// Immediate Multiplication -instruct mulI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{ - match(Set dst (MulI src1 src2)); - - size(4); - format %{ "MULX $src1,$src2,$dst" %} - opcode(Assembler::mulx_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(imul_reg_imm); -%} - -instruct mulL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (MulL src1 src2)); - ins_cost(DEFAULT_COST * 5); - size(4); - format %{ "MULX $src1,$src2,$dst\t! long" %} - opcode(Assembler::mulx_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(mulL_reg_reg); -%} - -// Immediate Multiplication -instruct mulL_reg_imm13(iRegL dst, iRegL src1, immL13 src2) %{ - match(Set dst (MulL src1 src2)); - ins_cost(DEFAULT_COST * 5); - size(4); - format %{ "MULX $src1,$src2,$dst" %} - opcode(Assembler::mulx_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(mulL_reg_imm); -%} - -// Integer Division -// Register Division -instruct divI_reg_reg(iRegI dst, iRegIsafe src1, iRegIsafe src2) %{ - match(Set dst (DivI src1 src2)); - ins_cost((2+71)*DEFAULT_COST); - - format %{ "SRA $src2,0,$src2\n\t" - "SRA $src1,0,$src1\n\t" - "SDIVX $src1,$src2,$dst" %} - ins_encode( idiv_reg( src1, src2, dst ) ); - ins_pipe(sdiv_reg_reg); -%} - -// Immediate Division -instruct divI_reg_imm13(iRegI dst, iRegIsafe src1, immI13 src2) %{ - match(Set dst (DivI src1 src2)); - ins_cost((2+71)*DEFAULT_COST); - - format %{ "SRA $src1,0,$src1\n\t" - "SDIVX $src1,$src2,$dst" %} - ins_encode( idiv_imm( src1, src2, dst ) ); - ins_pipe(sdiv_reg_imm); -%} - -//----------Div-By-10-Expansion------------------------------------------------ -// Extract hi bits of a 32x32->64 bit multiply. -// Expand rule only, not matched -instruct mul_hi(iRegIsafe dst, iRegIsafe src1, iRegIsafe src2 ) %{ - effect( DEF dst, USE src1, USE src2 ); - format %{ "MULX $src1,$src2,$dst\t! Used in div-by-10\n\t" - "SRLX $dst,#32,$dst\t\t! Extract only hi word of result" %} - ins_encode( enc_mul_hi(dst,src1,src2)); - ins_pipe(sdiv_reg_reg); -%} - -// Magic constant, reciprocal of 10 -instruct loadConI_x66666667(iRegIsafe dst) %{ - effect( DEF dst ); - - size(8); - format %{ "SET 0x66666667,$dst\t! Used in div-by-10" %} - ins_encode( Set32(0x66666667, dst) ); - ins_pipe(ialu_hi_lo_reg); -%} - -// Register Shift Right Arithmetic Long by 32-63 -instruct sra_31( iRegI dst, iRegI src ) %{ - effect( DEF dst, USE src ); - format %{ "SRA $src,31,$dst\t! Used in div-by-10" %} - ins_encode( form3_rs1_rd_copysign_hi(src,dst) ); - ins_pipe(ialu_reg_reg); -%} - -// Arithmetic Shift Right by 8-bit immediate -instruct sra_reg_2( iRegI dst, iRegI src ) %{ - effect( DEF dst, USE src ); - format %{ "SRA $src,2,$dst\t! Used in div-by-10" %} - opcode(Assembler::sra_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src, 0x2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Integer DIV with 10 -instruct divI_10( iRegI dst, iRegIsafe src, immI10 div ) %{ - match(Set dst (DivI src div)); - ins_cost((6+6)*DEFAULT_COST); - expand %{ - iRegIsafe tmp1; // Killed temps; - iRegIsafe tmp2; // Killed temps; - iRegI tmp3; // Killed temps; - iRegI tmp4; // Killed temps; - loadConI_x66666667( tmp1 ); // SET 0x66666667 -> tmp1 - mul_hi( tmp2, src, tmp1 ); // MUL hibits(src * tmp1) -> tmp2 - sra_31( tmp3, src ); // SRA src,31 -> tmp3 - sra_reg_2( tmp4, tmp2 ); // SRA tmp2,2 -> tmp4 - subI_reg_reg( dst,tmp4,tmp3); // SUB tmp4 - tmp3 -> dst - %} -%} - -// Register Long Division -instruct divL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (DivL src1 src2)); - ins_cost(DEFAULT_COST*71); - size(4); - format %{ "SDIVX $src1,$src2,$dst\t! long" %} - opcode(Assembler::sdivx_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(divL_reg_reg); -%} - -// Register Long Division -instruct divL_reg_imm13(iRegL dst, iRegL src1, immL13 src2) %{ - match(Set dst (DivL src1 src2)); - ins_cost(DEFAULT_COST*71); - size(4); - format %{ "SDIVX $src1,$src2,$dst\t! long" %} - opcode(Assembler::sdivx_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(divL_reg_imm); -%} - -// Integer Remainder -// Register Remainder -instruct modI_reg_reg(iRegI dst, iRegIsafe src1, iRegIsafe src2, o7RegP temp, flagsReg ccr ) %{ - match(Set dst (ModI src1 src2)); - effect( KILL ccr, KILL temp); - - format %{ "SREM $src1,$src2,$dst" %} - ins_encode( irem_reg(src1, src2, dst, temp) ); - ins_pipe(sdiv_reg_reg); -%} - -// Immediate Remainder -instruct modI_reg_imm13(iRegI dst, iRegIsafe src1, immI13 src2, o7RegP temp, flagsReg ccr ) %{ - match(Set dst (ModI src1 src2)); - effect( KILL ccr, KILL temp); - - format %{ "SREM $src1,$src2,$dst" %} - ins_encode( irem_imm(src1, src2, dst, temp) ); - ins_pipe(sdiv_reg_imm); -%} - -// Register Long Remainder -instruct divL_reg_reg_1(iRegL dst, iRegL src1, iRegL src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "SDIVX $src1,$src2,$dst\t! long" %} - opcode(Assembler::sdivx_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(divL_reg_reg); -%} - -// Register Long Division -instruct divL_reg_imm13_1(iRegL dst, iRegL src1, immL13 src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "SDIVX $src1,$src2,$dst\t! long" %} - opcode(Assembler::sdivx_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(divL_reg_imm); -%} - -instruct mulL_reg_reg_1(iRegL dst, iRegL src1, iRegL src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "MULX $src1,$src2,$dst\t! long" %} - opcode(Assembler::mulx_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(mulL_reg_reg); -%} - -// Immediate Multiplication -instruct mulL_reg_imm13_1(iRegL dst, iRegL src1, immL13 src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "MULX $src1,$src2,$dst" %} - opcode(Assembler::mulx_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(mulL_reg_imm); -%} - -instruct subL_reg_reg_1(iRegL dst, iRegL src1, iRegL src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "SUB $src1,$src2,$dst\t! long" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -instruct subL_reg_reg_2(iRegL dst, iRegL src1, iRegL src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "SUB $src1,$src2,$dst\t! long" %} - opcode(Assembler::sub_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Long Remainder -instruct modL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (ModL src1 src2)); - ins_cost(DEFAULT_COST*(71 + 6 + 1)); - expand %{ - iRegL tmp1; - iRegL tmp2; - divL_reg_reg_1(tmp1, src1, src2); - mulL_reg_reg_1(tmp2, tmp1, src2); - subL_reg_reg_1(dst, src1, tmp2); - %} -%} - -// Register Long Remainder -instruct modL_reg_imm13(iRegL dst, iRegL src1, immL13 src2) %{ - match(Set dst (ModL src1 src2)); - ins_cost(DEFAULT_COST*(71 + 6 + 1)); - expand %{ - iRegL tmp1; - iRegL tmp2; - divL_reg_imm13_1(tmp1, src1, src2); - mulL_reg_imm13_1(tmp2, tmp1, src2); - subL_reg_reg_2 (dst, src1, tmp2); - %} -%} - -// Integer Shift Instructions -// Register Shift Left -instruct shlI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (LShiftI src1 src2)); - - size(4); - format %{ "SLL $src1,$src2,$dst" %} - opcode(Assembler::sll_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Shift Left Immediate -instruct shlI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{ - match(Set dst (LShiftI src1 src2)); - - size(4); - format %{ "SLL $src1,$src2,$dst" %} - opcode(Assembler::sll_op3, Assembler::arith_op); - ins_encode( form3_rs1_imm5_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Shift Left -instruct shlL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{ - match(Set dst (LShiftL src1 src2)); - - size(4); - format %{ "SLLX $src1,$src2,$dst" %} - opcode(Assembler::sllx_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Shift Left Immediate -instruct shlL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{ - match(Set dst (LShiftL src1 src2)); - - size(4); - format %{ "SLLX $src1,$src2,$dst" %} - opcode(Assembler::sllx_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Arithmetic Shift Right -instruct sarI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (RShiftI src1 src2)); - size(4); - format %{ "SRA $src1,$src2,$dst" %} - opcode(Assembler::sra_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Arithmetic Shift Right Immediate -instruct sarI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{ - match(Set dst (RShiftI src1 src2)); - - size(4); - format %{ "SRA $src1,$src2,$dst" %} - opcode(Assembler::sra_op3, Assembler::arith_op); - ins_encode( form3_rs1_imm5_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Shift Right Arithmatic Long -instruct sarL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{ - match(Set dst (RShiftL src1 src2)); - - size(4); - format %{ "SRAX $src1,$src2,$dst" %} - opcode(Assembler::srax_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Shift Left Immediate -instruct sarL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{ - match(Set dst (RShiftL src1 src2)); - - size(4); - format %{ "SRAX $src1,$src2,$dst" %} - opcode(Assembler::srax_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Shift Right -instruct shrI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (URShiftI src1 src2)); - - size(4); - format %{ "SRL $src1,$src2,$dst" %} - opcode(Assembler::srl_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Shift Right Immediate -instruct shrI_reg_imm5(iRegI dst, iRegI src1, immU5 src2) %{ - match(Set dst (URShiftI src1 src2)); - - size(4); - format %{ "SRL $src1,$src2,$dst" %} - opcode(Assembler::srl_op3, Assembler::arith_op); - ins_encode( form3_rs1_imm5_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Shift Right -instruct shrL_reg_reg(iRegL dst, iRegL src1, iRegI src2) %{ - match(Set dst (URShiftL src1 src2)); - - size(4); - format %{ "SRLX $src1,$src2,$dst" %} - opcode(Assembler::srlx_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Register Shift Right Immediate -instruct shrL_reg_imm6(iRegL dst, iRegL src1, immU6 src2) %{ - match(Set dst (URShiftL src1 src2)); - - size(4); - format %{ "SRLX $src1,$src2,$dst" %} - opcode(Assembler::srlx_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Shift Right Immediate with a CastP2X -instruct shrP_reg_imm6(iRegL dst, iRegP src1, immU6 src2) %{ - match(Set dst (URShiftL (CastP2X src1) src2)); - size(4); - format %{ "SRLX $src1,$src2,$dst\t! Cast ptr $src1 to long and shift" %} - opcode(Assembler::srlx_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_imm6_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - - -//----------Floating Point Arithmetic Instructions----------------------------- - -// Add float single precision -instruct addF_reg_reg(regF dst, regF src1, regF src2) %{ - match(Set dst (AddF src1 src2)); - - size(4); - format %{ "FADDS $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fadds_opf); - ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst)); - ins_pipe(faddF_reg_reg); -%} - -// Add float double precision -instruct addD_reg_reg(regD dst, regD src1, regD src2) %{ - match(Set dst (AddD src1 src2)); - - size(4); - format %{ "FADDD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::faddd_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(faddD_reg_reg); -%} - -// Sub float single precision -instruct subF_reg_reg(regF dst, regF src1, regF src2) %{ - match(Set dst (SubF src1 src2)); - - size(4); - format %{ "FSUBS $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fsubs_opf); - ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst)); - ins_pipe(faddF_reg_reg); -%} - -// Sub float double precision -instruct subD_reg_reg(regD dst, regD src1, regD src2) %{ - match(Set dst (SubD src1 src2)); - - size(4); - format %{ "FSUBD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fsubd_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(faddD_reg_reg); -%} - -// Mul float single precision -instruct mulF_reg_reg(regF dst, regF src1, regF src2) %{ - match(Set dst (MulF src1 src2)); - - size(4); - format %{ "FMULS $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmuls_opf); - ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst)); - ins_pipe(fmulF_reg_reg); -%} - -// Mul float double precision -instruct mulD_reg_reg(regD dst, regD src1, regD src2) %{ - match(Set dst (MulD src1 src2)); - - size(4); - format %{ "FMULD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmuld_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(fmulD_reg_reg); -%} - -// Div float single precision -instruct divF_reg_reg(regF dst, regF src1, regF src2) %{ - match(Set dst (DivF src1 src2)); - - size(4); - format %{ "FDIVS $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdivs_opf); - ins_encode(form3_opf_rs1F_rs2F_rdF(src1, src2, dst)); - ins_pipe(fdivF_reg_reg); -%} - -// Div float double precision -instruct divD_reg_reg(regD dst, regD src1, regD src2) %{ - match(Set dst (DivD src1 src2)); - - size(4); - format %{ "FDIVD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdivd_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(fdivD_reg_reg); -%} - -// Absolute float double precision -instruct absD_reg(regD dst, regD src) %{ - match(Set dst (AbsD src)); - - format %{ "FABSd $src,$dst" %} - ins_encode(fabsd(dst, src)); - ins_pipe(faddD_reg); -%} - -// Absolute float single precision -instruct absF_reg(regF dst, regF src) %{ - match(Set dst (AbsF src)); - - format %{ "FABSs $src,$dst" %} - ins_encode(fabss(dst, src)); - ins_pipe(faddF_reg); -%} - -instruct negF_reg(regF dst, regF src) %{ - match(Set dst (NegF src)); - - size(4); - format %{ "FNEGs $src,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fnegs_opf); - ins_encode(form3_opf_rs2F_rdF(src, dst)); - ins_pipe(faddF_reg); -%} - -instruct negD_reg(regD dst, regD src) %{ - match(Set dst (NegD src)); - - format %{ "FNEGd $src,$dst" %} - ins_encode(fnegd(dst, src)); - ins_pipe(faddD_reg); -%} - -// Sqrt float double precision -instruct sqrtF_reg_reg(regF dst, regF src) %{ - match(Set dst (ConvD2F (SqrtD (ConvF2D src)))); - - size(4); - format %{ "FSQRTS $src,$dst" %} - ins_encode(fsqrts(dst, src)); - ins_pipe(fdivF_reg_reg); -%} - -// Sqrt float double precision -instruct sqrtD_reg_reg(regD dst, regD src) %{ - match(Set dst (SqrtD src)); - - size(4); - format %{ "FSQRTD $src,$dst" %} - ins_encode(fsqrtd(dst, src)); - ins_pipe(fdivD_reg_reg); -%} - -// Single/Double precision fused floating-point multiply-add (d = a * b + c). -instruct fmaF_regx4(regF dst, regF a, regF b, regF c) %{ - predicate(UseFMA); - match(Set dst (FmaF c (Binary a b))); - format %{ "fmadds $a,$b,$c,$dst\t# $dst = $a * $b + $c" %} - ins_encode(fmadds(dst, a, b, c)); - ins_pipe(fmaF_regx4); -%} - -instruct fmaD_regx4(regD dst, regD a, regD b, regD c) %{ - predicate(UseFMA); - match(Set dst (FmaD c (Binary a b))); - format %{ "fmaddd $a,$b,$c,$dst\t# $dst = $a * $b + $c" %} - ins_encode(fmaddd(dst, a, b, c)); - ins_pipe(fmaD_regx4); -%} - -// Additional patterns matching complement versions that we can map directly to -// variants of the fused multiply-add instructions. - -// Single/Double precision fused floating-point multiply-sub (d = a * b - c) -instruct fmsubF_regx4(regF dst, regF a, regF b, regF c) %{ - predicate(UseFMA); - match(Set dst (FmaF (NegF c) (Binary a b))); - format %{ "fmsubs $a,$b,$c,$dst\t# $dst = $a * $b - $c" %} - ins_encode(fmsubs(dst, a, b, c)); - ins_pipe(fmaF_regx4); -%} - -instruct fmsubD_regx4(regD dst, regD a, regD b, regD c) %{ - predicate(UseFMA); - match(Set dst (FmaD (NegD c) (Binary a b))); - format %{ "fmsubd $a,$b,$c,$dst\t# $dst = $a * $b - $c" %} - ins_encode(fmsubd(dst, a, b, c)); - ins_pipe(fmaD_regx4); -%} - -// Single/Double precision fused floating-point neg. multiply-add, -// d = -1 * a * b - c = -(a * b + c) -instruct fnmaddF_regx4(regF dst, regF a, regF b, regF c) %{ - predicate(UseFMA); - match(Set dst (FmaF (NegF c) (Binary (NegF a) b))); - match(Set dst (FmaF (NegF c) (Binary a (NegF b)))); - format %{ "fnmadds $a,$b,$c,$dst\t# $dst = -($a * $b + $c)" %} - ins_encode(fnmadds(dst, a, b, c)); - ins_pipe(fmaF_regx4); -%} - -instruct fnmaddD_regx4(regD dst, regD a, regD b, regD c) %{ - predicate(UseFMA); - match(Set dst (FmaD (NegD c) (Binary (NegD a) b))); - match(Set dst (FmaD (NegD c) (Binary a (NegD b)))); - format %{ "fnmaddd $a,$b,$c,$dst\t# $dst = -($a * $b + $c)" %} - ins_encode(fnmaddd(dst, a, b, c)); - ins_pipe(fmaD_regx4); -%} - -// Single/Double precision fused floating-point neg. multiply-sub, -// d = -1 * a * b + c = -(a * b - c) -instruct fnmsubF_regx4(regF dst, regF a, regF b, regF c) %{ - predicate(UseFMA); - match(Set dst (FmaF c (Binary (NegF a) b))); - match(Set dst (FmaF c (Binary a (NegF b)))); - format %{ "fnmsubs $a,$b,$c,$dst\t# $dst = -($a * $b - $c)" %} - ins_encode(fnmsubs(dst, a, b, c)); - ins_pipe(fmaF_regx4); -%} - -instruct fnmsubD_regx4(regD dst, regD a, regD b, regD c) %{ - predicate(UseFMA); - match(Set dst (FmaD c (Binary (NegD a) b))); - match(Set dst (FmaD c (Binary a (NegD b)))); - format %{ "fnmsubd $a,$b,$c,$dst\t# $dst = -($a * $b - $c)" %} - ins_encode(fnmsubd(dst, a, b, c)); - ins_pipe(fmaD_regx4); -%} - -//----------Logical Instructions----------------------------------------------- -// And Instructions -// Register And -instruct andI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (AndI src1 src2)); - - size(4); - format %{ "AND $src1,$src2,$dst" %} - opcode(Assembler::and_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Immediate And -instruct andI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{ - match(Set dst (AndI src1 src2)); - - size(4); - format %{ "AND $src1,$src2,$dst" %} - opcode(Assembler::and_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register And Long -instruct andL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (AndL src1 src2)); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "AND $src1,$src2,$dst\t! long" %} - opcode(Assembler::and_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -instruct andL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{ - match(Set dst (AndL src1 con)); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "AND $src1,$con,$dst\t! long" %} - opcode(Assembler::and_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, con, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Or Instructions -// Register Or -instruct orI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (OrI src1 src2)); - - size(4); - format %{ "OR $src1,$src2,$dst" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Immediate Or -instruct orI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{ - match(Set dst (OrI src1 src2)); - - size(4); - format %{ "OR $src1,$src2,$dst" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Or Long -instruct orL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (OrL src1 src2)); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "OR $src1,$src2,$dst\t! long" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -instruct orL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{ - match(Set dst (OrL src1 con)); - ins_cost(DEFAULT_COST*2); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "OR $src1,$con,$dst\t! long" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, con, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -instruct orL_reg_castP2X(iRegL dst, iRegL src1, sp_ptr_RegP src2) %{ - match(Set dst (OrL src1 (CastP2X src2))); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "OR $src1,$src2,$dst\t! long" %} - opcode(Assembler::or_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Xor Instructions -// Register Xor -instruct xorI_reg_reg(iRegI dst, iRegI src1, iRegI src2) %{ - match(Set dst (XorI src1 src2)); - - size(4); - format %{ "XOR $src1,$src2,$dst" %} - opcode(Assembler::xor_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Immediate Xor -instruct xorI_reg_imm13(iRegI dst, iRegI src1, immI13 src2) %{ - match(Set dst (XorI src1 src2)); - - size(4); - format %{ "XOR $src1,$src2,$dst" %} - opcode(Assembler::xor_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -// Register Xor Long -instruct xorL_reg_reg(iRegL dst, iRegL src1, iRegL src2) %{ - match(Set dst (XorL src1 src2)); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "XOR $src1,$src2,$dst\t! long" %} - opcode(Assembler::xor_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src1, src2, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -instruct xorL_reg_imm13(iRegL dst, iRegL src1, immL13 con) %{ - match(Set dst (XorL src1 con)); - - ins_cost(DEFAULT_COST); - size(4); - format %{ "XOR $src1,$con,$dst\t! long" %} - opcode(Assembler::xor_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( src1, con, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -//----------Convert to Boolean------------------------------------------------- -// Nice hack for 32-bit tests but doesn't work for -// 64-bit pointers. -instruct convI2B( iRegI dst, iRegI src, flagsReg ccr ) %{ - match(Set dst (Conv2B src)); - effect( KILL ccr ); - ins_cost(DEFAULT_COST*2); - format %{ "CMP R_G0,$src\n\t" - "ADDX R_G0,0,$dst" %} - ins_encode( enc_to_bool( src, dst ) ); - ins_pipe(ialu_reg_ialu); -%} - -instruct convP2B( iRegI dst, iRegP src ) %{ - match(Set dst (Conv2B src)); - ins_cost(DEFAULT_COST*2); - format %{ "MOV $src,$dst\n\t" - "MOVRNZ $src,1,$dst" %} - ins_encode( form3_g0_rs2_rd_move( src, dst ), enc_convP2B( dst, src ) ); - ins_pipe(ialu_clr_and_mover); -%} - -instruct cmpLTMask0( iRegI dst, iRegI src, immI0 zero, flagsReg ccr ) %{ - match(Set dst (CmpLTMask src zero)); - effect(KILL ccr); - size(4); - format %{ "SRA $src,#31,$dst\t# cmpLTMask0" %} - ins_encode %{ - __ sra($src$$Register, 31, $dst$$Register); - %} - ins_pipe(ialu_reg_imm); -%} - -instruct cmpLTMask_reg_reg( iRegI dst, iRegI p, iRegI q, flagsReg ccr ) %{ - match(Set dst (CmpLTMask p q)); - effect( KILL ccr ); - ins_cost(DEFAULT_COST*4); - format %{ "CMP $p,$q\n\t" - "MOV #0,$dst\n\t" - "BLT,a .+8\n\t" - "MOV #-1,$dst" %} - ins_encode( enc_ltmask(p,q,dst) ); - ins_pipe(ialu_reg_reg_ialu); -%} - -instruct cadd_cmpLTMask( iRegI p, iRegI q, iRegI y, iRegI tmp, flagsReg ccr ) %{ - match(Set p (AddI (AndI (CmpLTMask p q) y) (SubI p q))); - effect(KILL ccr, TEMP tmp); - ins_cost(DEFAULT_COST*3); - - format %{ "SUBcc $p,$q,$p\t! p' = p-q\n\t" - "ADD $p,$y,$tmp\t! g3=p-q+y\n\t" - "MOVlt $tmp,$p\t! p' < 0 ? p'+y : p'" %} - ins_encode(enc_cadd_cmpLTMask(p, q, y, tmp)); - ins_pipe(cadd_cmpltmask); -%} - -instruct and_cmpLTMask(iRegI p, iRegI q, iRegI y, flagsReg ccr) %{ - match(Set p (AndI (CmpLTMask p q) y)); - effect(KILL ccr); - ins_cost(DEFAULT_COST*3); - - format %{ "CMP $p,$q\n\t" - "MOV $y,$p\n\t" - "MOVge G0,$p" %} - ins_encode %{ - __ cmp($p$$Register, $q$$Register); - __ mov($y$$Register, $p$$Register); - __ movcc(Assembler::greaterEqual, false, Assembler::icc, G0, $p$$Register); - %} - ins_pipe(ialu_reg_reg_ialu); -%} - -//----------------------------------------------------------------- -// Direct raw moves between float and general registers using VIS3. - -// ins_pipe(faddF_reg); -instruct MoveF2I_reg_reg(iRegI dst, regF src) %{ - predicate(UseVIS >= 3); - match(Set dst (MoveF2I src)); - - format %{ "MOVSTOUW $src,$dst\t! MoveF2I" %} - ins_encode %{ - __ movstouw($src$$FloatRegister, $dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct MoveI2F_reg_reg(regF dst, iRegI src) %{ - predicate(UseVIS >= 3); - match(Set dst (MoveI2F src)); - - format %{ "MOVWTOS $src,$dst\t! MoveI2F" %} - ins_encode %{ - __ movwtos($src$$Register, $dst$$FloatRegister); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct MoveD2L_reg_reg(iRegL dst, regD src) %{ - predicate(UseVIS >= 3); - match(Set dst (MoveD2L src)); - - format %{ "MOVDTOX $src,$dst\t! MoveD2L" %} - ins_encode %{ - __ movdtox(as_DoubleFloatRegister($src$$reg), $dst$$Register); - %} - ins_pipe(ialu_reg_reg); -%} - -instruct MoveL2D_reg_reg(regD dst, iRegL src) %{ - predicate(UseVIS >= 3); - match(Set dst (MoveL2D src)); - - format %{ "MOVXTOD $src,$dst\t! MoveL2D" %} - ins_encode %{ - __ movxtod($src$$Register, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(ialu_reg_reg); -%} - - -// Raw moves between float and general registers using stack. - -instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{ - match(Set dst (MoveF2I src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "LDUW $src,$dst\t! MoveF2I" %} - opcode(Assembler::lduw_op3); - ins_encode(simple_form3_mem_reg( src, dst ) ); - ins_pipe(iload_mem); -%} - -instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ - match(Set dst (MoveI2F src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "LDF $src,$dst\t! MoveI2F" %} - opcode(Assembler::ldf_op3); - ins_encode(simple_form3_mem_reg(src, dst)); - ins_pipe(floadF_stk); -%} - -instruct MoveD2L_stack_reg(iRegL dst, stackSlotD src) %{ - match(Set dst (MoveD2L src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "LDX $src,$dst\t! MoveD2L" %} - opcode(Assembler::ldx_op3); - ins_encode(simple_form3_mem_reg( src, dst ) ); - ins_pipe(iload_mem); -%} - -instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ - match(Set dst (MoveL2D src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "LDDF $src,$dst\t! MoveL2D" %} - opcode(Assembler::lddf_op3); - ins_encode(simple_form3_mem_reg(src, dst)); - ins_pipe(floadD_stk); -%} - -instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ - match(Set dst (MoveF2I src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "STF $src,$dst\t! MoveF2I" %} - opcode(Assembler::stf_op3); - ins_encode(simple_form3_mem_reg(dst, src)); - ins_pipe(fstoreF_stk_reg); -%} - -instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ - match(Set dst (MoveI2F src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "STW $src,$dst\t! MoveI2F" %} - opcode(Assembler::stw_op3); - ins_encode(simple_form3_mem_reg( dst, src ) ); - ins_pipe(istore_mem_reg); -%} - -instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ - match(Set dst (MoveD2L src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "STDF $src,$dst\t! MoveD2L" %} - opcode(Assembler::stdf_op3); - ins_encode(simple_form3_mem_reg(dst, src)); - ins_pipe(fstoreD_stk_reg); -%} - -instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ - match(Set dst (MoveL2D src)); - effect(DEF dst, USE src); - ins_cost(MEMORY_REF_COST); - - format %{ "STX $src,$dst\t! MoveL2D" %} - opcode(Assembler::stx_op3); - ins_encode(simple_form3_mem_reg( dst, src ) ); - ins_pipe(istore_mem_reg); -%} - - -//----------Arithmetic Conversion Instructions--------------------------------- -// The conversions operations are all Alpha sorted. Please keep it that way! - -instruct convD2F_reg(regF dst, regD src) %{ - match(Set dst (ConvD2F src)); - size(4); - format %{ "FDTOS $src,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdtos_opf); - ins_encode(form3_opf_rs2D_rdF(src, dst)); - ins_pipe(fcvtD2F); -%} - - -// Convert a double to an int in a float register. -// If the double is a NAN, stuff a zero in instead. -instruct convD2I_helper(regF dst, regD src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FDTOI $src,$dst\t! convert in delay slot\n\t" - "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t" - "FSUBs $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_d2i_helper(src,dst)); - ins_pipe(fcvtD2I); -%} - -instruct convD2I_stk(stackSlotI dst, regD src) %{ - match(Set dst (ConvD2I src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regF tmp; - convD2I_helper(tmp, src); - regF_to_stkI(dst, tmp); - %} -%} - -instruct convD2I_reg(iRegI dst, regD src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvD2I src)); - ins_cost(DEFAULT_COST*2 + BRANCH_COST); - expand %{ - regF tmp; - convD2I_helper(tmp, src); - MoveF2I_reg_reg(dst, tmp); - %} -%} - - -// Convert a double to a long in a double register. -// If the double is a NAN, stuff a zero in instead. -instruct convD2L_helper(regD dst, regD src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FDTOX $src,$dst\t! convert in delay slot\n\t" - "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t" - "FSUBd $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_d2l_helper(src,dst)); - ins_pipe(fcvtD2L); -%} - -instruct convD2L_stk(stackSlotL dst, regD src) %{ - match(Set dst (ConvD2L src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regD tmp; - convD2L_helper(tmp, src); - regD_to_stkL(dst, tmp); - %} -%} - -instruct convD2L_reg(iRegL dst, regD src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvD2L src)); - ins_cost(DEFAULT_COST*2 + BRANCH_COST); - expand %{ - regD tmp; - convD2L_helper(tmp, src); - MoveD2L_reg_reg(dst, tmp); - %} -%} - - -instruct convF2D_reg(regD dst, regF src) %{ - match(Set dst (ConvF2D src)); - format %{ "FSTOD $src,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fstod_opf); - ins_encode(form3_opf_rs2F_rdD(src, dst)); - ins_pipe(fcvtF2D); -%} - - -// Convert a float to an int in a float register. -// If the float is a NAN, stuff a zero in instead. -instruct convF2I_helper(regF dst, regF src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FSTOI $src,$dst\t! convert in delay slot\n\t" - "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t" - "FSUBs $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_f2i_helper(src,dst)); - ins_pipe(fcvtF2I); -%} - -instruct convF2I_stk(stackSlotI dst, regF src) %{ - match(Set dst (ConvF2I src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regF tmp; - convF2I_helper(tmp, src); - regF_to_stkI(dst, tmp); - %} -%} - -instruct convF2I_reg(iRegI dst, regF src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvF2I src)); - ins_cost(DEFAULT_COST*2 + BRANCH_COST); - expand %{ - regF tmp; - convF2I_helper(tmp, src); - MoveF2I_reg_reg(dst, tmp); - %} -%} - - -// Convert a float to a long in a float register. -// If the float is a NAN, stuff a zero in instead. -instruct convF2L_helper(regD dst, regF src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FSTOX $src,$dst\t! convert in delay slot\n\t" - "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t" - "FSUBd $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_f2l_helper(src,dst)); - ins_pipe(fcvtF2L); -%} - -instruct convF2L_stk(stackSlotL dst, regF src) %{ - match(Set dst (ConvF2L src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regD tmp; - convF2L_helper(tmp, src); - regD_to_stkL(dst, tmp); - %} -%} - -instruct convF2L_reg(iRegL dst, regF src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvF2L src)); - ins_cost(DEFAULT_COST*2 + BRANCH_COST); - expand %{ - regD tmp; - convF2L_helper(tmp, src); - MoveD2L_reg_reg(dst, tmp); - %} -%} - - -instruct convI2D_helper(regD dst, regF tmp) %{ - effect(USE tmp, DEF dst); - format %{ "FITOD $tmp,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf); - ins_encode(form3_opf_rs2F_rdD(tmp, dst)); - ins_pipe(fcvtI2D); -%} - -instruct convI2D_stk(stackSlotI src, regD dst) %{ - match(Set dst (ConvI2D src)); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - expand %{ - regF tmp; - stkI_to_regF(tmp, src); - convI2D_helper(dst, tmp); - %} -%} - -instruct convI2D_reg(regD_low dst, iRegI src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvI2D src)); - expand %{ - regF tmp; - MoveI2F_reg_reg(tmp, src); - convI2D_helper(dst, tmp); - %} -%} - -instruct convI2D_mem(regD_low dst, memory mem) %{ - match(Set dst (ConvI2D (LoadI mem))); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - format %{ "LDF $mem,$dst\n\t" - "FITOD $dst,$dst" %} - opcode(Assembler::ldf_op3, Assembler::fitod_opf); - ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); - ins_pipe(floadF_mem); -%} - - -instruct convI2F_helper(regF dst, regF tmp) %{ - effect(DEF dst, USE tmp); - format %{ "FITOS $tmp,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitos_opf); - ins_encode(form3_opf_rs2F_rdF(tmp, dst)); - ins_pipe(fcvtI2F); -%} - -instruct convI2F_stk(regF dst, stackSlotI src) %{ - match(Set dst (ConvI2F src)); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - expand %{ - regF tmp; - stkI_to_regF(tmp,src); - convI2F_helper(dst, tmp); - %} -%} - -instruct convI2F_reg(regF dst, iRegI src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvI2F src)); - ins_cost(DEFAULT_COST); - expand %{ - regF tmp; - MoveI2F_reg_reg(tmp, src); - convI2F_helper(dst, tmp); - %} -%} - -instruct convI2F_mem( regF dst, memory mem ) %{ - match(Set dst (ConvI2F (LoadI mem))); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - format %{ "LDF $mem,$dst\n\t" - "FITOS $dst,$dst" %} - opcode(Assembler::ldf_op3, Assembler::fitos_opf); - ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); - ins_pipe(floadF_mem); -%} - - -instruct convI2L_reg(iRegL dst, iRegI src) %{ - match(Set dst (ConvI2L src)); - size(4); - format %{ "SRA $src,0,$dst\t! int->long" %} - opcode(Assembler::sra_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Zero-extend convert int to long -instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{ - match(Set dst (AndL (ConvI2L src) mask) ); - size(4); - format %{ "SRL $src,0,$dst\t! zero-extend int to long" %} - opcode(Assembler::srl_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); - ins_pipe(ialu_reg_reg); -%} - -// Zero-extend long -instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{ - match(Set dst (AndL src mask) ); - size(4); - format %{ "SRL $src,0,$dst\t! zero-extend long" %} - opcode(Assembler::srl_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); - ins_pipe(ialu_reg_reg); -%} - - -//----------- -// Long to Double conversion using V8 opcodes. -// Still useful because cheetah traps and becomes -// amazingly slow for some common numbers. - -// Magic constant, 0x43300000 -instruct loadConI_x43300000(iRegI dst) %{ - effect(DEF dst); - size(4); - format %{ "SETHI HI(0x43300000),$dst\t! 2^52" %} - ins_encode(SetHi22(0x43300000, dst)); - ins_pipe(ialu_none); -%} - -// Magic constant, 0x41f00000 -instruct loadConI_x41f00000(iRegI dst) %{ - effect(DEF dst); - size(4); - format %{ "SETHI HI(0x41f00000),$dst\t! 2^32" %} - ins_encode(SetHi22(0x41f00000, dst)); - ins_pipe(ialu_none); -%} - -// Construct a double from two float halves -instruct regDHi_regDLo_to_regD(regD_low dst, regD_low src1, regD_low src2) %{ - effect(DEF dst, USE src1, USE src2); - size(8); - format %{ "FMOVS $src1.hi,$dst.hi\n\t" - "FMOVS $src2.lo,$dst.lo" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmovs_opf); - ins_encode(form3_opf_rs2D_hi_rdD_hi(src1, dst), form3_opf_rs2D_lo_rdD_lo(src2, dst)); - ins_pipe(faddD_reg_reg); -%} - -// Convert integer in high half of a double register (in the lower half of -// the double register file) to double -instruct convI2D_regDHi_regD(regD dst, regD_low src) %{ - effect(DEF dst, USE src); - size(4); - format %{ "FITOD $src,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf); - ins_encode(form3_opf_rs2D_rdD(src, dst)); - ins_pipe(fcvtLHi2D); -%} - -// Add float double precision -instruct addD_regD_regD(regD dst, regD src1, regD src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "FADDD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::faddd_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(faddD_reg_reg); -%} - -// Sub float double precision -instruct subD_regD_regD(regD dst, regD src1, regD src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "FSUBD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fsubd_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(faddD_reg_reg); -%} - -// Mul float double precision -instruct mulD_regD_regD(regD dst, regD src1, regD src2) %{ - effect(DEF dst, USE src1, USE src2); - size(4); - format %{ "FMULD $src1,$src2,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fmuld_opf); - ins_encode(form3_opf_rs1D_rs2D_rdD(src1, src2, dst)); - ins_pipe(fmulD_reg_reg); -%} - -// Long to Double conversion using fast fxtof -instruct convL2D_helper(regD dst, regD tmp) %{ - effect(DEF dst, USE tmp); - size(4); - format %{ "FXTOD $tmp,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fxtod_opf); - ins_encode(form3_opf_rs2D_rdD(tmp, dst)); - ins_pipe(fcvtL2D); -%} - -instruct convL2D_stk_fast_fxtof(regD dst, stackSlotL src) %{ - match(Set dst (ConvL2D src)); - ins_cost(DEFAULT_COST + 3 * MEMORY_REF_COST); - expand %{ - regD tmp; - stkL_to_regD(tmp, src); - convL2D_helper(dst, tmp); - %} -%} - -instruct convL2D_reg(regD dst, iRegL src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvL2D src)); - expand %{ - regD tmp; - MoveL2D_reg_reg(tmp, src); - convL2D_helper(dst, tmp); - %} -%} - -// Long to Float conversion using fast fxtof -instruct convL2F_helper(regF dst, regD tmp) %{ - effect(DEF dst, USE tmp); - size(4); - format %{ "FXTOS $tmp,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fxtos_opf); - ins_encode(form3_opf_rs2D_rdF(tmp, dst)); - ins_pipe(fcvtL2F); -%} - -instruct convL2F_stk_fast_fxtof(regF dst, stackSlotL src) %{ - match(Set dst (ConvL2F src)); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - expand %{ - regD tmp; - stkL_to_regD(tmp, src); - convL2F_helper(dst, tmp); - %} -%} - -instruct convL2F_reg(regF dst, iRegL src) %{ - predicate(UseVIS >= 3); - match(Set dst (ConvL2F src)); - ins_cost(DEFAULT_COST); - expand %{ - regD tmp; - MoveL2D_reg_reg(tmp, src); - convL2F_helper(dst, tmp); - %} -%} - -//----------- - -instruct convL2I_reg(iRegI dst, iRegL src) %{ - match(Set dst (ConvL2I src)); - size(4); - format %{ "SRA $src,R_G0,$dst\t! long->int" %} - ins_encode( form3_rs1_rd_signextend_lo1( src, dst ) ); - ins_pipe(ialu_reg); -%} - -// Register Shift Right Immediate -instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{ - match(Set dst (ConvL2I (RShiftL src cnt))); - - size(4); - format %{ "SRAX $src,$cnt,$dst" %} - opcode(Assembler::srax_op3, Assembler::arith_op); - ins_encode( form3_sd_rs1_imm6_rd( src, cnt, dst ) ); - ins_pipe(ialu_reg_imm); -%} - -//----------Control Flow Instructions------------------------------------------ -// Compare Instructions -// Compare Integers -instruct compI_iReg(flagsReg icc, iRegI op1, iRegI op2) %{ - match(Set icc (CmpI op1 op2)); - effect( DEF icc, USE op1, USE op2 ); - - size(4); - format %{ "CMP $op1,$op2" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compU_iReg(flagsRegU icc, iRegI op1, iRegI op2) %{ - match(Set icc (CmpU op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! unsigned" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compUL_iReg(flagsRegUL xcc, iRegL op1, iRegL op2) %{ - match(Set xcc (CmpUL op1 op2)); - effect(DEF xcc, USE op1, USE op2); - - size(4); - format %{ "CMP $op1,$op2\t! unsigned long" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode(form3_rs1_rs2_rd(op1, op2, R_G0)); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compI_iReg_imm13(flagsReg icc, iRegI op1, immI13 op2) %{ - match(Set icc (CmpI op1 op2)); - effect( DEF icc, USE op1 ); - - size(4); - format %{ "CMP $op1,$op2" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_imm); -%} - -instruct testI_reg_reg( flagsReg icc, iRegI op1, iRegI op2, immI0 zero ) %{ - match(Set icc (CmpI (AndI op1 op2) zero)); - - size(4); - format %{ "BTST $op2,$op1" %} - opcode(Assembler::andcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg_zero); -%} - -instruct testI_reg_imm( flagsReg icc, iRegI op1, immI13 op2, immI0 zero ) %{ - match(Set icc (CmpI (AndI op1 op2) zero)); - - size(4); - format %{ "BTST $op2,$op1" %} - opcode(Assembler::andcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_imm_zero); -%} - -instruct compL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2 ) %{ - match(Set xcc (CmpL op1 op2)); - effect( DEF xcc, USE op1, USE op2 ); - - size(4); - format %{ "CMP $op1,$op2\t\t! long" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compL_reg_con(flagsRegL xcc, iRegL op1, immL13 con) %{ - match(Set xcc (CmpL op1 con)); - effect( DEF xcc, USE op1, USE con ); - - size(4); - format %{ "CMP $op1,$con\t\t! long" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, con, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct testL_reg_reg(flagsRegL xcc, iRegL op1, iRegL op2, immL0 zero) %{ - match(Set xcc (CmpL (AndL op1 op2) zero)); - effect( DEF xcc, USE op1, USE op2 ); - - size(4); - format %{ "BTST $op1,$op2\t\t! long" %} - opcode(Assembler::andcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -// useful for checking the alignment of a pointer: -instruct testL_reg_con(flagsRegL xcc, iRegL op1, immL13 con, immL0 zero) %{ - match(Set xcc (CmpL (AndL op1 con) zero)); - effect( DEF xcc, USE op1, USE con ); - - size(4); - format %{ "BTST $op1,$con\t\t! long" %} - opcode(Assembler::andcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, con, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compU_iReg_imm13(flagsRegU icc, iRegI op1, immU12 op2 ) %{ - match(Set icc (CmpU op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! unsigned" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_imm); -%} - -instruct compUL_iReg_imm13(flagsRegUL xcc, iRegL op1, immUL12 op2) %{ - match(Set xcc (CmpUL op1 op2)); - effect(DEF xcc, USE op1, USE op2); - - size(4); - format %{ "CMP $op1,$op2\t! unsigned long" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode(form3_rs1_simm13_rd(op1, op2, R_G0)); - ins_pipe(ialu_cconly_reg_imm); -%} - -// Compare Pointers -instruct compP_iRegP(flagsRegP pcc, iRegP op1, iRegP op2 ) %{ - match(Set pcc (CmpP op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! ptr" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compP_iRegP_imm13(flagsRegP pcc, iRegP op1, immP13 op2 ) %{ - match(Set pcc (CmpP op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! ptr" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_imm); -%} - -// Compare Narrow oops -instruct compN_iRegN(flagsReg icc, iRegN op1, iRegN op2 ) %{ - match(Set icc (CmpN op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! compressed ptr" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_reg); -%} - -instruct compN_iRegN_immN0(flagsReg icc, iRegN op1, immN0 op2 ) %{ - match(Set icc (CmpN op1 op2)); - - size(4); - format %{ "CMP $op1,$op2\t! compressed ptr" %} - opcode(Assembler::subcc_op3, Assembler::arith_op); - ins_encode( form3_rs1_simm13_rd( op1, op2, R_G0 ) ); - ins_pipe(ialu_cconly_reg_imm); -%} - -//----------Max and Min-------------------------------------------------------- -// Min Instructions -// Conditional move for min -instruct cmovI_reg_lt( iRegI op2, iRegI op1, flagsReg icc ) %{ - effect( USE_DEF op2, USE op1, USE icc ); - - size(4); - format %{ "MOVlt icc,$op1,$op2\t! min" %} - opcode(Assembler::less); - ins_encode( enc_cmov_reg_minmax(op2,op1) ); - ins_pipe(ialu_reg_flags); -%} - -// Min Register with Register. -instruct minI_eReg(iRegI op1, iRegI op2) %{ - match(Set op2 (MinI op1 op2)); - ins_cost(DEFAULT_COST*2); - expand %{ - flagsReg icc; - compI_iReg(icc,op1,op2); - cmovI_reg_lt(op2,op1,icc); - %} -%} - -// Max Instructions -// Conditional move for max -instruct cmovI_reg_gt( iRegI op2, iRegI op1, flagsReg icc ) %{ - effect( USE_DEF op2, USE op1, USE icc ); - format %{ "MOVgt icc,$op1,$op2\t! max" %} - opcode(Assembler::greater); - ins_encode( enc_cmov_reg_minmax(op2,op1) ); - ins_pipe(ialu_reg_flags); -%} - -// Max Register with Register -instruct maxI_eReg(iRegI op1, iRegI op2) %{ - match(Set op2 (MaxI op1 op2)); - ins_cost(DEFAULT_COST*2); - expand %{ - flagsReg icc; - compI_iReg(icc,op1,op2); - cmovI_reg_gt(op2,op1,icc); - %} -%} - - -//----------Float Compares---------------------------------------------------- -// Compare floating, generate condition code -instruct cmpF_cc(flagsRegF fcc, regF src1, regF src2) %{ - match(Set fcc (CmpF src1 src2)); - - size(4); - format %{ "FCMPs $fcc,$src1,$src2" %} - opcode(Assembler::fpop2_op3, Assembler::arith_op, Assembler::fcmps_opf); - ins_encode( form3_opf_rs1F_rs2F_fcc( src1, src2, fcc ) ); - ins_pipe(faddF_fcc_reg_reg_zero); -%} - -instruct cmpD_cc(flagsRegF fcc, regD src1, regD src2) %{ - match(Set fcc (CmpD src1 src2)); - - size(4); - format %{ "FCMPd $fcc,$src1,$src2" %} - opcode(Assembler::fpop2_op3, Assembler::arith_op, Assembler::fcmpd_opf); - ins_encode( form3_opf_rs1D_rs2D_fcc( src1, src2, fcc ) ); - ins_pipe(faddD_fcc_reg_reg_zero); -%} - - -// Compare floating, generate -1,0,1 -instruct cmpF_reg(iRegI dst, regF src1, regF src2, flagsRegF0 fcc0) %{ - match(Set dst (CmpF3 src1 src2)); - effect(KILL fcc0); - ins_cost(DEFAULT_COST*3+BRANCH_COST*3); - format %{ "fcmpl $dst,$src1,$src2" %} - // Primary = float - opcode( true ); - ins_encode( floating_cmp( dst, src1, src2 ) ); - ins_pipe( floating_cmp ); -%} - -instruct cmpD_reg(iRegI dst, regD src1, regD src2, flagsRegF0 fcc0) %{ - match(Set dst (CmpD3 src1 src2)); - effect(KILL fcc0); - ins_cost(DEFAULT_COST*3+BRANCH_COST*3); - format %{ "dcmpl $dst,$src1,$src2" %} - // Primary = double (not float) - opcode( false ); - ins_encode( floating_cmp( dst, src1, src2 ) ); - ins_pipe( floating_cmp ); -%} - -//----------Branches--------------------------------------------------------- -// Jump -// (compare 'operand indIndex' and 'instruct addP_reg_reg' above) -instruct jumpXtnd(iRegX switch_val, o7RegI table) %{ - match(Jump switch_val); - effect(TEMP table); - - ins_cost(350); - - format %{ "ADD $constanttablebase, $constantoffset, O7\n\t" - "LD [O7 + $switch_val], O7\n\t" - "JUMP O7" %} - ins_encode %{ - // Calculate table address into a register. - Register table_reg; - Register label_reg = O7; - // If we are calculating the size of this instruction don't trust - // zero offsets because they might change when - // MachConstantBaseNode decides to optimize the constant table - // base. - if ((constant_offset() == 0) && !Compile::current()->output()->in_scratch_emit_size()) { - table_reg = $constanttablebase; - } else { - table_reg = O7; - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset, O7); - __ add($constanttablebase, con_offset, table_reg); - } - - // Jump to base address + switch value - __ ld_ptr(table_reg, $switch_val$$Register, label_reg); - __ jmp(label_reg, G0); - __ delayed()->nop(); - %} - ins_pipe(ialu_reg_reg); -%} - -// Direct Branch. Use V8 version with longer range. -instruct branch(label labl) %{ - match(Goto); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BA $labl" %} - ins_encode %{ - Label* L = $labl$$label; - __ ba(*L); - __ delayed()->nop(); - %} - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br); -%} - -// Direct Branch, short with no delay slot -instruct branch_short(label labl) %{ - match(Goto); - predicate(UseCBCond); - effect(USE labl); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "BA $labl\t! short branch" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ ba_short(*L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_imm); -%} - -// Conditional Direct Branch -instruct branchCon(cmpOp cmp, flagsReg icc, label labl) %{ - match(If cmp icc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BP$cmp $icc,$labl" %} - // Prim = bits 24-22, Secnd = bits 31-30 - ins_encode( enc_bp( labl, cmp, icc ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -instruct branchConU(cmpOpU cmp, flagsRegU icc, label labl) %{ - match(If cmp icc); - effect(USE labl); - - ins_cost(BRANCH_COST); - format %{ "BP$cmp $icc,$labl" %} - // Prim = bits 24-22, Secnd = bits 31-30 - ins_encode( enc_bp( labl, cmp, icc ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -instruct branchConP(cmpOpP cmp, flagsRegP pcc, label labl) %{ - match(If cmp pcc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BP$cmp $pcc,$labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - - __ bp( (Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -instruct branchConF(cmpOpF cmp, flagsRegF fcc, label labl) %{ - match(If cmp fcc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "FBP$cmp $fcc,$labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - - __ fbp( (Assembler::Condition)($cmp$$cmpcode), false, (Assembler::CC)($fcc$$reg), predict_taken, *L); - __ delayed()->nop(); - %} - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_fcc); -%} - -instruct branchLoopEnd(cmpOp cmp, flagsReg icc, label labl) %{ - match(CountedLoopEnd cmp icc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BP$cmp $icc,$labl\t! Loop end" %} - // Prim = bits 24-22, Secnd = bits 31-30 - ins_encode( enc_bp( labl, cmp, icc ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -instruct branchLoopEndU(cmpOpU cmp, flagsRegU icc, label labl) %{ - match(CountedLoopEnd cmp icc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BP$cmp $icc,$labl\t! Loop end" %} - // Prim = bits 24-22, Secnd = bits 31-30 - ins_encode( enc_bp( labl, cmp, icc ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -// Compare and branch instructions -instruct cmpI_reg_branch(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{ - match(If cmp (CmpI op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! int\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpI_imm_branch(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{ - match(If cmp (CmpI op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! int\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$constant); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_imm); -%} - -instruct cmpU_reg_branch(cmpOpU cmp, iRegI op1, iRegI op2, label labl, flagsRegU icc) %{ - match(If cmp (CmpU op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! unsigned\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpU_imm_branch(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU icc) %{ - match(If cmp (CmpU op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! unsigned\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$constant); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_imm); -%} - -instruct cmpUL_reg_branch(cmpOpU cmp, iRegL op1, iRegL op2, label labl, flagsRegUL xcc) %{ - match(If cmp (CmpUL op1 op2)); - effect(USE labl, KILL xcc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! unsigned long\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpUL_imm_branch(cmpOpU cmp, iRegL op1, immL5 op2, label labl, flagsRegUL xcc) %{ - match(If cmp (CmpUL op1 op2)); - effect(USE labl, KILL xcc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! unsigned long\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$constant); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_imm); -%} - -instruct cmpL_reg_branch(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{ - match(If cmp (CmpL op1 op2)); - effect(USE labl, KILL xcc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! long\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpL_imm_branch(cmpOp cmp, iRegL op1, immL5 op2, label labl, flagsRegL xcc) %{ - match(If cmp (CmpL op1 op2)); - effect(USE labl, KILL xcc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! long\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$constant); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_imm); -%} - -// Compare Pointers and branch -instruct cmpP_reg_branch(cmpOpP cmp, iRegP op1, iRegP op2, label labl, flagsRegP pcc) %{ - match(If cmp (CmpP op1 op2)); - effect(USE labl, KILL pcc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! ptr\n\t" - "B$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpP_null_branch(cmpOpP cmp, iRegP op1, immP0 null, label labl, flagsRegP pcc) %{ - match(If cmp (CmpP op1 null)); - effect(USE labl, KILL pcc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,0\t! ptr\n\t" - "B$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, G0); - // bpr() is not used here since it has shorter distance. - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::ptr_cc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpN_reg_branch(cmpOp cmp, iRegN op1, iRegN op2, label labl, flagsReg icc) %{ - match(If cmp (CmpN op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! compressed ptr\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpN_null_branch(cmpOp cmp, iRegN op1, immN0 null, label labl, flagsReg icc) %{ - match(If cmp (CmpN op1 null)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,0\t! compressed ptr\n\t" - "BP$cmp $labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, G0); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -// Loop back branch -instruct cmpI_reg_branchLoopEnd(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{ - match(CountedLoopEnd cmp (CmpI op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! int\n\t" - "BP$cmp $labl\t! Loop end" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$Register); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_reg); -%} - -instruct cmpI_imm_branchLoopEnd(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{ - match(CountedLoopEnd cmp (CmpI op1 op2)); - effect(USE labl, KILL icc); - - size(12); - ins_cost(BRANCH_COST); - format %{ "CMP $op1,$op2\t! int\n\t" - "BP$cmp $labl\t! Loop end" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - __ cmp($op1$$Register, $op2$$constant); - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::icc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_pipe(cmp_br_reg_imm); -%} - -// Short compare and branch instructions -instruct cmpI_reg_branch_short(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{ - match(If cmp (CmpI op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! int" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpI_imm_branch_short(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{ - match(If cmp (CmpI op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! int" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_imm); -%} - -instruct cmpU_reg_branch_short(cmpOpU cmp, iRegI op1, iRegI op2, label labl, flagsRegU icc) %{ - match(If cmp (CmpU op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! unsigned" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpU_imm_branch_short(cmpOpU cmp, iRegI op1, immI5 op2, label labl, flagsRegU icc) %{ - match(If cmp (CmpU op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! unsigned" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_imm); -%} - -instruct cmpUL_reg_branch_short(cmpOpU cmp, iRegL op1, iRegL op2, label labl, flagsRegUL xcc) %{ - match(If cmp (CmpUL op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL xcc); - - size(4); - ins_cost(BRANCH_COST); - format %{ "CXB$cmp $op1,$op2,$labl\t! unsigned long" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpUL_imm_branch_short(cmpOpU cmp, iRegL op1, immL5 op2, label labl, flagsRegUL xcc) %{ - match(If cmp (CmpUL op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL xcc); - - size(4); - ins_cost(BRANCH_COST); - format %{ "CXB$cmp $op1,$op2,$labl\t! unsigned long" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$constant, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_imm); -%} - -instruct cmpL_reg_branch_short(cmpOp cmp, iRegL op1, iRegL op2, label labl, flagsRegL xcc) %{ - match(If cmp (CmpL op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL xcc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CXB$cmp $op1,$op2,$labl\t! long" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpL_imm_branch_short(cmpOp cmp, iRegL op1, immL5 op2, label labl, flagsRegL xcc) %{ - match(If cmp (CmpL op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL xcc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CXB$cmp $op1,$op2,$labl\t! long" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::xcc, $op1$$Register, $op2$$constant, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_imm); -%} - -// Compare Pointers and branch -instruct cmpP_reg_branch_short(cmpOpP cmp, iRegP op1, iRegP op2, label labl, flagsRegP pcc) %{ - match(If cmp (CmpP op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL pcc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CXB$cmp $op1,$op2,$labl\t! ptr" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::ptr_cc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpP_null_branch_short(cmpOpP cmp, iRegP op1, immP0 null, label labl, flagsRegP pcc) %{ - match(If cmp (CmpP op1 null)); - predicate(UseCBCond); - effect(USE labl, KILL pcc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CXB$cmp $op1,0,$labl\t! ptr" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::ptr_cc, $op1$$Register, G0, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpN_reg_branch_short(cmpOp cmp, iRegN op1, iRegN op2, label labl, flagsReg icc) %{ - match(If cmp (CmpN op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! compressed ptr" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpN_null_branch_short(cmpOp cmp, iRegN op1, immN0 null, label labl, flagsReg icc) %{ - match(If cmp (CmpN op1 null)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,0,$labl\t! compressed ptr" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, G0, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -// Loop back branch -instruct cmpI_reg_branchLoopEnd_short(cmpOp cmp, iRegI op1, iRegI op2, label labl, flagsReg icc) %{ - match(CountedLoopEnd cmp (CmpI op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! Loop end" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$Register, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_reg); -%} - -instruct cmpI_imm_branchLoopEnd_short(cmpOp cmp, iRegI op1, immI5 op2, label labl, flagsReg icc) %{ - match(CountedLoopEnd cmp (CmpI op1 op2)); - predicate(UseCBCond); - effect(USE labl, KILL icc); - - size(4); // Assuming no NOP inserted. - ins_cost(BRANCH_COST); - format %{ "CWB$cmp $op1,$op2,$labl\t! Loop end" %} - ins_encode %{ - Label* L = $labl$$label; - assert(__ use_cbcond(*L), "back to back cbcond"); - __ cbcond((Assembler::Condition)($cmp$$cmpcode), Assembler::icc, $op1$$Register, $op2$$constant, *L); - %} - ins_short_branch(1); - ins_avoid_back_to_back(AVOID_BEFORE_AND_AFTER); - ins_pipe(cbcond_reg_imm); -%} - -// Branch-on-register tests all 64 bits. We assume that values -// in 64-bit registers always remains zero or sign extended -// unless our code munges the high bits. Interrupts can chop -// the high order bits to zero or sign at any time. -instruct branchCon_regI(cmpOp_reg cmp, iRegI op1, immI0 zero, label labl) %{ - match(If cmp (CmpI op1 zero)); - predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf)); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BR$cmp $op1,$labl" %} - ins_encode( enc_bpr( labl, cmp, op1 ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_reg); -%} - -instruct branchCon_regP(cmpOp_reg cmp, iRegP op1, immP0 null, label labl) %{ - match(If cmp (CmpP op1 null)); - predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf)); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BR$cmp $op1,$labl" %} - ins_encode( enc_bpr( labl, cmp, op1 ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_reg); -%} - -instruct branchCon_regL(cmpOp_reg cmp, iRegL op1, immL0 zero, label labl) %{ - match(If cmp (CmpL op1 zero)); - predicate(can_branch_register(_kids[0]->_leaf, _kids[1]->_leaf)); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BR$cmp $op1,$labl" %} - ins_encode( enc_bpr( labl, cmp, op1 ) ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_reg); -%} - - -// ============================================================================ -// Long Compare -// -// Currently we hold longs in 2 registers. Comparing such values efficiently -// is tricky. The flavor of compare used depends on whether we are testing -// for LT, LE, or EQ. For a simple LT test we can check just the sign bit. -// The GE test is the negated LT test. The LE test can be had by commuting -// the operands (yielding a GE test) and then negating; negate again for the -// GT test. The EQ test is done by ORcc'ing the high and low halves, and the -// NE test is negated from that. - -// Due to a shortcoming in the ADLC, it mixes up expressions like: -// (foo (CmpI (CmpL X Y) 0)) and (bar (CmpI (CmpL X 0L) 0)). Note the -// difference between 'Y' and '0L'. The tree-matches for the CmpI sections -// are collapsed internally in the ADLC's dfa-gen code. The match for -// (CmpI (CmpL X Y) 0) is silently replaced with (CmpI (CmpL X 0L) 0) and the -// foo match ends up with the wrong leaf. One fix is to not match both -// reg-reg and reg-zero forms of long-compare. This is unfortunate because -// both forms beat the trinary form of long-compare and both are very useful -// on Intel which has so few registers. - -instruct branchCon_long(cmpOp cmp, flagsRegL xcc, label labl) %{ - match(If cmp xcc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BP$cmp $xcc,$labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - - __ bp( (Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -instruct branchConU_long(cmpOpU cmp, flagsRegUL xcc, label labl) %{ - match(If cmp xcc); - effect(USE labl); - - size(8); - ins_cost(BRANCH_COST); - format %{ "BP$cmp $xcc,$labl" %} - ins_encode %{ - Label* L = $labl$$label; - Assembler::Predict predict_taken = - cbuf.is_backward_branch(*L) ? Assembler::pt : Assembler::pn; - - __ bp((Assembler::Condition)($cmp$$cmpcode), false, Assembler::xcc, predict_taken, *L); - __ delayed()->nop(); - %} - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(br_cc); -%} - -// Manifest a CmpL3 result in an integer register. Very painful. -// This is the test to avoid. -instruct cmpL3_reg_reg(iRegI dst, iRegL src1, iRegL src2, flagsReg ccr ) %{ - match(Set dst (CmpL3 src1 src2) ); - effect( KILL ccr ); - ins_cost(6*DEFAULT_COST); - size(24); - format %{ "CMP $src1,$src2\t\t! long\n" - "\tBLT,a,pn done\n" - "\tMOV -1,$dst\t! delay slot\n" - "\tBGT,a,pn done\n" - "\tMOV 1,$dst\t! delay slot\n" - "\tCLR $dst\n" - "done:" %} - ins_encode( cmpl_flag(src1,src2,dst) ); - ins_pipe(cmpL_reg); -%} - -// Conditional move -instruct cmovLL_reg(cmpOp cmp, flagsRegL xcc, iRegL dst, iRegL src) %{ - match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $xcc,$src,$dst\t! long" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovLL_imm(cmpOp cmp, flagsRegL xcc, iRegL dst, immL0 src) %{ - match(Set dst (CMoveL (Binary cmp xcc) (Binary dst src))); - ins_cost(140); - format %{ "MOV$cmp $xcc,$src,$dst\t! long" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovIL_reg(cmpOp cmp, flagsRegL xcc, iRegI dst, iRegI src) %{ - match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovIL_imm(cmpOp cmp, flagsRegL xcc, iRegI dst, immI11 src) %{ - match(Set dst (CMoveI (Binary cmp xcc) (Binary dst src))); - ins_cost(140); - format %{ "MOV$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovNL_reg(cmpOp cmp, flagsRegL xcc, iRegN dst, iRegN src) %{ - match(Set dst (CMoveN (Binary cmp xcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovPL_reg(cmpOp cmp, flagsRegL xcc, iRegP dst, iRegP src) %{ - match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - ins_cost(150); - format %{ "MOV$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmov_reg(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_reg); -%} - -instruct cmovPL_imm(cmpOp cmp, flagsRegL xcc, iRegP dst, immP0 src) %{ - match(Set dst (CMoveP (Binary cmp xcc) (Binary dst src))); - ins_cost(140); - format %{ "MOV$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmov_imm(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(ialu_imm); -%} - -instruct cmovFL_reg(cmpOp cmp, flagsRegL xcc, regF dst, regF src) %{ - match(Set dst (CMoveF (Binary cmp xcc) (Binary dst src))); - ins_cost(150); - opcode(0x101); - format %{ "FMOVS$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(int_conditional_float_move); -%} - -instruct cmovDL_reg(cmpOp cmp, flagsRegL xcc, regD dst, regD src) %{ - match(Set dst (CMoveD (Binary cmp xcc) (Binary dst src))); - ins_cost(150); - opcode(0x102); - format %{ "FMOVD$cmp $xcc,$src,$dst" %} - ins_encode( enc_cmovf_reg(cmp,dst,src, (Assembler::xcc)) ); - ins_pipe(int_conditional_float_move); -%} - -// ============================================================================ -// Safepoint Instruction -instruct safePoint_poll(iRegP poll) %{ - match(SafePoint poll); - effect(USE poll); - - size(4); - format %{ "LDX [$poll],R_G0\t! Safepoint: poll for GC" %} - ins_encode %{ - __ relocate(relocInfo::poll_type); - __ ld_ptr($poll$$Register, 0, G0); - %} - ins_pipe(loadPollP); -%} - -// ============================================================================ -// Call Instructions -// Call Java Static Instruction -instruct CallStaticJavaDirect( method meth ) %{ - match(CallStaticJava); - predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke()); - effect(USE meth); - - size(8); - ins_cost(CALL_COST); - format %{ "CALL,static ; NOP ==> " %} - ins_encode( Java_Static_Call( meth ), call_epilog ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(simple_call); -%} - -// Call Java Static Instruction (method handle version) -instruct CallStaticJavaHandle(method meth, l7RegP l7_mh_SP_save) %{ - match(CallStaticJava); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - effect(USE meth, KILL l7_mh_SP_save); - - size(16); - ins_cost(CALL_COST); - format %{ "CALL,static/MethodHandle" %} - ins_encode(preserve_SP, Java_Static_Call(meth), restore_SP, call_epilog); - ins_pipe(simple_call); -%} - -// Call Java Dynamic Instruction -instruct CallDynamicJavaDirect( method meth ) %{ - match(CallDynamicJava); - effect(USE meth); - - ins_cost(CALL_COST); - format %{ "SET (empty),R_G5\n\t" - "CALL,dynamic ; NOP ==> " %} - ins_encode( Java_Dynamic_Call( meth ), call_epilog ); - ins_pipe(call); -%} - -// Call Runtime Instruction -instruct CallRuntimeDirect(method meth, l7RegP l7) %{ - match(CallRuntime); - effect(USE meth, KILL l7); - ins_cost(CALL_COST); - format %{ "CALL,runtime" %} - ins_encode( Java_To_Runtime( meth ), - call_epilog, adjust_long_from_native_call ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(simple_call); -%} - -// Call runtime without safepoint - same as CallRuntime -instruct CallLeafDirect(method meth, l7RegP l7) %{ - match(CallLeaf); - effect(USE meth, KILL l7); - ins_cost(CALL_COST); - format %{ "CALL,runtime leaf" %} - ins_encode( Java_To_Runtime( meth ), - call_epilog, - adjust_long_from_native_call ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(simple_call); -%} - -// Call runtime without safepoint - same as CallLeaf -instruct CallLeafNoFPDirect(method meth, l7RegP l7) %{ - match(CallLeafNoFP); - effect(USE meth, KILL l7); - ins_cost(CALL_COST); - format %{ "CALL,runtime leaf nofp" %} - ins_encode( Java_To_Runtime( meth ), - call_epilog, - adjust_long_from_native_call ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(simple_call); -%} - -// Tail Call; Jump from runtime stub to Java code. -// Also known as an 'interprocedural jump'. -// Target of jump will eventually return to caller. -// TailJump below removes the return address. -instruct TailCalljmpInd(g3RegP jump_target, inline_cache_regP method_oop) %{ - match(TailCall jump_target method_oop ); - - ins_cost(CALL_COST); - format %{ "Jmp $jump_target ; NOP \t! $method_oop holds method oop" %} - ins_encode(form_jmpl(jump_target)); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(tail_call); -%} - - -// Return Instruction -instruct Ret() %{ - match(Return); - - // The epilogue node did the ret already. - size(0); - format %{ "! return" %} - ins_encode(); - ins_pipe(empty); -%} - - -// Tail Jump; remove the return address; jump to target. -// TailCall above leaves the return address around. -// TailJump is used in only one place, the rethrow_Java stub (fancy_jump=2). -// ex_oop (Exception Oop) is needed in %o0 at the jump. As there would be a -// "restore" before this instruction (in Epilogue), we need to materialize it -// in %i0. -instruct tailjmpInd(g1RegP jump_target, i0RegP ex_oop) %{ - match( TailJump jump_target ex_oop ); - ins_cost(CALL_COST); - format %{ "! discard R_O7\n\t" - "Jmp $jump_target ; ADD O7,8,O1 \t! $ex_oop holds exc. oop" %} - ins_encode(form_jmpl_set_exception_pc(jump_target)); - // opcode(Assembler::jmpl_op3, Assembler::arith_op); - // The hack duplicates the exception oop into G3, so that CreateEx can use it there. - // ins_encode( form3_rs1_simm13_rd( jump_target, 0x00, R_G0 ), move_return_pc_to_o1() ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(tail_call); -%} - -// Create exception oop: created by stack-crawling runtime code. -// Created exception is now available to this handler, and is setup -// just prior to jumping to this handler. No code emitted. -instruct CreateException( o0RegP ex_oop ) -%{ - match(Set ex_oop (CreateEx)); - ins_cost(0); - - size(0); - // use the following format syntax - format %{ "! exception oop is in R_O0; no code emitted" %} - ins_encode(); - ins_pipe(empty); -%} - - -// Rethrow exception: -// The exception oop will come in the first argument position. -// Then JUMP (not call) to the rethrow stub code. -instruct RethrowException() -%{ - match(Rethrow); - ins_cost(CALL_COST); - - // use the following format syntax - format %{ "Jmp rethrow_stub" %} - ins_encode(enc_rethrow); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(tail_call); -%} - - -// Die now -instruct ShouldNotReachHere( ) -%{ - match(Halt); - ins_cost(CALL_COST); - - size(4); - // Use the following format syntax - format %{ "ILLTRAP ; ShouldNotReachHere" %} - ins_encode( form2_illtrap() ); - ins_pipe(tail_call); -%} - -// ============================================================================ -// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass -// array for an instance of the superklass. Set a hidden internal cache on a -// hit (cache is checked with exposed code in gen_subtype_check()). Return -// not zero for a miss or zero for a hit. The encoding ALSO sets flags. -instruct partialSubtypeCheck( o0RegP index, o1RegP sub, o2RegP super, flagsRegP pcc, o7RegP o7 ) %{ - match(Set index (PartialSubtypeCheck sub super)); - effect( KILL pcc, KILL o7 ); - ins_cost(DEFAULT_COST*10); - format %{ "CALL PartialSubtypeCheck\n\tNOP" %} - ins_encode( enc_PartialSubtypeCheck() ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(partial_subtype_check_pipe); -%} - -instruct partialSubtypeCheck_vs_zero( flagsRegP pcc, o1RegP sub, o2RegP super, immP0 zero, o0RegP idx, o7RegP o7 ) %{ - match(Set pcc (CmpP (PartialSubtypeCheck sub super) zero)); - effect( KILL idx, KILL o7 ); - ins_cost(DEFAULT_COST*10); - format %{ "CALL PartialSubtypeCheck\n\tNOP\t# (sets condition codes)" %} - ins_encode( enc_PartialSubtypeCheck() ); - ins_avoid_back_to_back(AVOID_BEFORE); - ins_pipe(partial_subtype_check_pipe); -%} - - -// ============================================================================ -// inlined locking and unlocking - -instruct cmpFastLock(flagsRegP pcc, iRegP object, o1RegP box, iRegP scratch2, o7RegP scratch ) %{ - match(Set pcc (FastLock object box)); - - effect(TEMP scratch2, USE_KILL box, KILL scratch); - ins_cost(100); - - format %{ "FASTLOCK $object,$box\t! kills $box,$scratch,$scratch2" %} - ins_encode( Fast_Lock(object, box, scratch, scratch2) ); - ins_pipe(long_memory_op); -%} - - -instruct cmpFastUnlock(flagsRegP pcc, iRegP object, o1RegP box, iRegP scratch2, o7RegP scratch ) %{ - match(Set pcc (FastUnlock object box)); - effect(TEMP scratch2, USE_KILL box, KILL scratch); - ins_cost(100); - - format %{ "FASTUNLOCK $object,$box\t! kills $box,$scratch,$scratch2" %} - ins_encode( Fast_Unlock(object, box, scratch, scratch2) ); - ins_pipe(long_memory_op); -%} - -// The encodings are generic. -instruct clear_array(iRegX cnt, iRegP base, iRegX temp, Universe dummy, flagsReg ccr) %{ - predicate(!use_block_zeroing(n->in(2)) ); - match(Set dummy (ClearArray cnt base)); - effect(TEMP temp, KILL ccr); - ins_cost(300); - format %{ "MOV $cnt,$temp\n" - "loop: SUBcc $temp,8,$temp\t! Count down a dword of bytes\n" - " BRge loop\t\t! Clearing loop\n" - " STX G0,[$base+$temp]\t! delay slot" %} - - ins_encode %{ - // Compiler ensures base is doubleword aligned and cnt is count of doublewords - Register nof_bytes_arg = $cnt$$Register; - Register nof_bytes_tmp = $temp$$Register; - Register base_pointer_arg = $base$$Register; - - Label loop; - __ mov(nof_bytes_arg, nof_bytes_tmp); - - // Loop and clear, walking backwards through the array. - // nof_bytes_tmp (if >0) is always the number of bytes to zero - __ bind(loop); - __ deccc(nof_bytes_tmp, 8); - __ br(Assembler::greaterEqual, true, Assembler::pt, loop); - __ delayed()-> stx(G0, base_pointer_arg, nof_bytes_tmp); - // %%%% this mini-loop must not cross a cache boundary! - %} - ins_pipe(long_memory_op); -%} - -instruct clear_array_bis(g1RegX cnt, o0RegP base, Universe dummy, flagsReg ccr) %{ - predicate(use_block_zeroing(n->in(2))); - match(Set dummy (ClearArray cnt base)); - effect(USE_KILL cnt, USE_KILL base, KILL ccr); - ins_cost(300); - format %{ "CLEAR [$base, $cnt]\t! ClearArray" %} - - ins_encode %{ - - assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation"); - Register to = $base$$Register; - Register count = $cnt$$Register; - - Label Ldone; - __ nop(); // Separate short branches - // Use BIS for zeroing (temp is not used). - __ bis_zeroing(to, count, G0, Ldone); - __ bind(Ldone); - - %} - ins_pipe(long_memory_op); -%} - -instruct clear_array_bis_2(g1RegX cnt, o0RegP base, iRegX tmp, Universe dummy, flagsReg ccr) %{ - predicate(use_block_zeroing(n->in(2)) && !Assembler::is_simm13((int)BlockZeroingLowLimit)); - match(Set dummy (ClearArray cnt base)); - effect(TEMP tmp, USE_KILL cnt, USE_KILL base, KILL ccr); - ins_cost(300); - format %{ "CLEAR [$base, $cnt]\t! ClearArray" %} - - ins_encode %{ - - assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation"); - Register to = $base$$Register; - Register count = $cnt$$Register; - Register temp = $tmp$$Register; - - Label Ldone; - __ nop(); // Separate short branches - // Use BIS for zeroing - __ bis_zeroing(to, count, temp, Ldone); - __ bind(Ldone); - - %} - ins_pipe(long_memory_op); -%} - -instruct string_compareL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result, - o7RegI tmp, flagsReg ccr) %{ - predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp); - ins_cost(300); - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - $tmp$$Register, $tmp$$Register, - $result$$Register, StrIntrinsicNode::LL); - %} - ins_pipe(long_memory_op); -%} - -instruct string_compareU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result, - o7RegI tmp, flagsReg ccr) %{ - predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp); - ins_cost(300); - format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - $tmp$$Register, $tmp$$Register, - $result$$Register, StrIntrinsicNode::UU); - %} - ins_pipe(long_memory_op); -%} - -instruct string_compareLU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result, - o7RegI tmp1, g1RegI tmp2, flagsReg ccr) %{ - predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp1, KILL tmp2); - ins_cost(300); - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %} - ins_encode %{ - __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, - $tmp1$$Register, $tmp2$$Register, - $result$$Register, StrIntrinsicNode::LU); - %} - ins_pipe(long_memory_op); -%} - -instruct string_compareUL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, notemp_iRegI result, - o7RegI tmp1, g1RegI tmp2, flagsReg ccr) %{ - predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); - match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ccr, KILL tmp1, KILL tmp2); - ins_cost(300); - format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %} - ins_encode %{ - __ string_compare($str2$$Register, $str1$$Register, - $cnt2$$Register, $cnt1$$Register, - $tmp1$$Register, $tmp2$$Register, - $result$$Register, StrIntrinsicNode::UL); - %} - ins_pipe(long_memory_op); -%} - -instruct string_equalsL(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result, - o7RegI tmp, flagsReg ccr) %{ - predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp, KILL ccr); - ins_cost(300); - format %{ "String Equals byte[] $str1,$str2,$cnt -> $result // KILL $tmp" %} - ins_encode %{ - __ array_equals(false, $str1$$Register, $str2$$Register, - $cnt$$Register, $tmp$$Register, - $result$$Register, true /* byte */); - %} - ins_pipe(long_memory_op); -%} - -instruct string_equalsU(o0RegP str1, o1RegP str2, g3RegI cnt, notemp_iRegI result, - o7RegI tmp, flagsReg ccr) %{ - predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL tmp, KILL ccr); - ins_cost(300); - format %{ "String Equals char[] $str1,$str2,$cnt -> $result // KILL $tmp" %} - ins_encode %{ - __ array_equals(false, $str1$$Register, $str2$$Register, - $cnt$$Register, $tmp$$Register, - $result$$Register, false /* byte */); - %} - ins_pipe(long_memory_op); -%} - -instruct array_equalsB(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result, - o7RegI tmp2, flagsReg ccr) %{ - predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); - match(Set result (AryEq ary1 ary2)); - effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr); - ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1,$tmp2" %} - ins_encode %{ - __ array_equals(true, $ary1$$Register, $ary2$$Register, - $tmp1$$Register, $tmp2$$Register, - $result$$Register, true /* byte */); - %} - ins_pipe(long_memory_op); -%} - -instruct array_equalsC(o0RegP ary1, o1RegP ary2, g3RegI tmp1, notemp_iRegI result, - o7RegI tmp2, flagsReg ccr) %{ - predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); - match(Set result (AryEq ary1 ary2)); - effect(USE_KILL ary1, USE_KILL ary2, KILL tmp1, KILL tmp2, KILL ccr); - ins_cost(300); - format %{ "Array Equals $ary1,$ary2 -> $result // KILL $tmp1,$tmp2" %} - ins_encode %{ - __ array_equals(true, $ary1$$Register, $ary2$$Register, - $tmp1$$Register, $tmp2$$Register, - $result$$Register, false /* byte */); - %} - ins_pipe(long_memory_op); -%} - -instruct has_negatives(o0RegP pAryR, g3RegI iSizeR, notemp_iRegI resultR, - iRegL tmp1L, iRegL tmp2L, iRegL tmp3L, iRegL tmp4L, - flagsReg ccr) -%{ - match(Set resultR (HasNegatives pAryR iSizeR)); - effect(TEMP resultR, TEMP tmp1L, TEMP tmp2L, TEMP tmp3L, TEMP tmp4L, USE pAryR, USE iSizeR, KILL ccr); - format %{ "has negatives byte[] $pAryR,$iSizeR -> $resultR // KILL $tmp1L,$tmp2L,$tmp3L,$tmp4L" %} - ins_encode %{ - __ has_negatives($pAryR$$Register, $iSizeR$$Register, - $resultR$$Register, - $tmp1L$$Register, $tmp2L$$Register, - $tmp3L$$Register, $tmp4L$$Register); - %} - ins_pipe(long_memory_op); -%} - -// char[] to byte[] compression -instruct string_compress(o0RegP src, o1RegP dst, g3RegI len, notemp_iRegI result, iRegL tmp, flagsReg ccr) %{ - predicate(UseVIS < 3); - match(Set result (StrCompressedCopy src (Binary dst len))); - effect(TEMP result, TEMP tmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr); - ins_cost(300); - format %{ "String Compress $src,$dst,$len -> $result // KILL $tmp" %} - ins_encode %{ - Label Ldone; - __ signx($len$$Register); - __ cmp_zero_and_br(Assembler::zero, $len$$Register, Ldone, false, Assembler::pn); - __ delayed()->mov($len$$Register, $result$$Register); // copy count - __ string_compress($src$$Register, $dst$$Register, $len$$Register, $result$$Register, $tmp$$Register, Ldone); - __ bind(Ldone); - %} - ins_pipe(long_memory_op); -%} - -// fast char[] to byte[] compression using VIS instructions -instruct string_compress_fast(o0RegP src, o1RegP dst, g3RegI len, notemp_iRegI result, - iRegL tmp1, iRegL tmp2, iRegL tmp3, iRegL tmp4, - regD ftmp1, regD ftmp2, regD ftmp3, flagsReg ccr) %{ - predicate(UseVIS >= 3); - match(Set result (StrCompressedCopy src (Binary dst len))); - effect(TEMP result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP ftmp1, TEMP ftmp2, TEMP ftmp3, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr); - ins_cost(300); - format %{ "String Compress Fast $src,$dst,$len -> $result // KILL $tmp1,$tmp2,$tmp3,$tmp4,$ftmp1,$ftmp2,$ftmp3" %} - ins_encode %{ - Label Ldone; - __ signx($len$$Register); - __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $result$$Register, - $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, - $ftmp1$$FloatRegister, $ftmp2$$FloatRegister, $ftmp3$$FloatRegister, Ldone); - __ cmp_and_brx_short($len$$Register, 0, Assembler::equal, Assembler::pn, Ldone); - __ string_compress($src$$Register, $dst$$Register, $len$$Register, $result$$Register, $tmp1$$Register, Ldone); - __ bind(Ldone); - %} - ins_pipe(long_memory_op); -%} - -// byte[] to char[] inflation -instruct string_inflate(Universe dummy, o0RegP src, o1RegP dst, g3RegI len, - iRegL tmp, flagsReg ccr) %{ - match(Set dummy (StrInflatedCopy src (Binary dst len))); - effect(TEMP tmp, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr); - ins_cost(300); - format %{ "String Inflate $src,$dst,$len // KILL $tmp" %} - ins_encode %{ - Label Ldone; - __ signx($len$$Register); - __ cmp_and_brx_short($len$$Register, 0, Assembler::equal, Assembler::pn, Ldone); - __ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register, Ldone); - __ bind(Ldone); - %} - ins_pipe(long_memory_op); -%} - -// fast byte[] to char[] inflation using VIS instructions -instruct string_inflate_fast(Universe dummy, o0RegP src, o1RegP dst, g3RegI len, - iRegL tmp, regD ftmp1, regD ftmp2, regD ftmp3, regD ftmp4, flagsReg ccr) %{ - predicate(UseVIS >= 3); - match(Set dummy (StrInflatedCopy src (Binary dst len))); - effect(TEMP tmp, TEMP ftmp1, TEMP ftmp2, TEMP ftmp3, TEMP ftmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL ccr); - ins_cost(300); - format %{ "String Inflate Fast $src,$dst,$len // KILL $tmp,$ftmp1,$ftmp2,$ftmp3,$ftmp4" %} - ins_encode %{ - Label Ldone; - __ signx($len$$Register); - __ string_inflate_16($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register, - $ftmp1$$FloatRegister, $ftmp2$$FloatRegister, $ftmp3$$FloatRegister, $ftmp4$$FloatRegister, Ldone); - __ cmp_and_brx_short($len$$Register, 0, Assembler::equal, Assembler::pn, Ldone); - __ string_inflate($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register, Ldone); - __ bind(Ldone); - %} - ins_pipe(long_memory_op); -%} - - -//---------- Zeros Count Instructions ------------------------------------------ - -instruct countLeadingZerosI(iRegIsafe dst, iRegI src, iRegI tmp, flagsReg cr) %{ - predicate(UsePopCountInstruction); // See Matcher::match_rule_supported - match(Set dst (CountLeadingZerosI src)); - effect(TEMP dst, TEMP tmp, KILL cr); - - // x |= (x >> 1); - // x |= (x >> 2); - // x |= (x >> 4); - // x |= (x >> 8); - // x |= (x >> 16); - // return (WORDBITS - popc(x)); - format %{ "SRL $src,1,$tmp\t! count leading zeros (int)\n\t" - "SRL $src,0,$dst\t! 32-bit zero extend\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRL $dst,2,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRL $dst,4,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRL $dst,8,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRL $dst,16,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "POPC $dst,$dst\n\t" - "MOV 32,$tmp\n\t" - "SUB $tmp,$dst,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - __ srl(Rsrc, 1, Rtmp); - __ srl(Rsrc, 0, Rdst); - __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 2, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 4, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 8, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ srl(Rdst, 16, Rtmp); - __ or3(Rdst, Rtmp, Rdst); - __ popc(Rdst, Rdst); - __ mov(BitsPerInt, Rtmp); - __ sub(Rtmp, Rdst, Rdst); - %} - ins_pipe(ialu_reg); -%} - -instruct countLeadingZerosL(iRegIsafe dst, iRegL src, iRegL tmp, flagsReg cr) %{ - predicate(UsePopCountInstruction); // See Matcher::match_rule_supported - match(Set dst (CountLeadingZerosL src)); - effect(TEMP dst, TEMP tmp, KILL cr); - - // x |= (x >> 1); - // x |= (x >> 2); - // x |= (x >> 4); - // x |= (x >> 8); - // x |= (x >> 16); - // x |= (x >> 32); - // return (WORDBITS - popc(x)); - format %{ "SRLX $src,1,$tmp\t! count leading zeros (long)\n\t" - "OR $src,$tmp,$dst\n\t" - "SRLX $dst,2,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRLX $dst,4,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRLX $dst,8,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRLX $dst,16,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "SRLX $dst,32,$tmp\n\t" - "OR $dst,$tmp,$dst\n\t" - "POPC $dst,$dst\n\t" - "MOV 64,$tmp\n\t" - "SUB $tmp,$dst,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - __ srlx(Rsrc, 1, Rtmp); - __ or3( Rsrc, Rtmp, Rdst); - __ srlx(Rdst, 2, Rtmp); - __ or3( Rdst, Rtmp, Rdst); - __ srlx(Rdst, 4, Rtmp); - __ or3( Rdst, Rtmp, Rdst); - __ srlx(Rdst, 8, Rtmp); - __ or3( Rdst, Rtmp, Rdst); - __ srlx(Rdst, 16, Rtmp); - __ or3( Rdst, Rtmp, Rdst); - __ srlx(Rdst, 32, Rtmp); - __ or3( Rdst, Rtmp, Rdst); - __ popc(Rdst, Rdst); - __ mov(BitsPerLong, Rtmp); - __ sub(Rtmp, Rdst, Rdst); - %} - ins_pipe(ialu_reg); -%} - -instruct countTrailingZerosI(iRegIsafe dst, iRegI src, flagsReg cr) %{ - predicate(UsePopCountInstruction); // See Matcher::match_rule_supported - match(Set dst (CountTrailingZerosI src)); - effect(TEMP dst, KILL cr); - - // return popc(~x & (x - 1)); - format %{ "SUB $src,1,$dst\t! count trailing zeros (int)\n\t" - "ANDN $dst,$src,$dst\n\t" - "SRL $dst,R_G0,$dst\n\t" - "POPC $dst,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rsrc = $src$$Register; - __ sub(Rsrc, 1, Rdst); - __ andn(Rdst, Rsrc, Rdst); - __ srl(Rdst, G0, Rdst); - __ popc(Rdst, Rdst); - %} - ins_pipe(ialu_reg); -%} - -instruct countTrailingZerosL(iRegIsafe dst, iRegL src, flagsReg cr) %{ - predicate(UsePopCountInstruction); // See Matcher::match_rule_supported - match(Set dst (CountTrailingZerosL src)); - effect(TEMP dst, KILL cr); - - // return popc(~x & (x - 1)); - format %{ "SUB $src,1,$dst\t! count trailing zeros (long)\n\t" - "ANDN $dst,$src,$dst\n\t" - "POPC $dst,$dst" %} - ins_encode %{ - Register Rdst = $dst$$Register; - Register Rsrc = $src$$Register; - __ sub(Rsrc, 1, Rdst); - __ andn(Rdst, Rsrc, Rdst); - __ popc(Rdst, Rdst); - %} - ins_pipe(ialu_reg); -%} - - -//---------- Population Count Instructions ------------------------------------- - -instruct popCountI(iRegIsafe dst, iRegI src) %{ - predicate(UsePopCountInstruction); - match(Set dst (PopCountI src)); - - format %{ "SRL $src, G0, $dst\t! clear upper word for 64 bit POPC\n\t" - "POPC $dst, $dst" %} - ins_encode %{ - __ srl($src$$Register, G0, $dst$$Register); - __ popc($dst$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Note: Long.bitCount(long) returns an int. -instruct popCountL(iRegIsafe dst, iRegL src) %{ - predicate(UsePopCountInstruction); - match(Set dst (PopCountL src)); - - format %{ "POPC $src, $dst" %} - ins_encode %{ - __ popc($src$$Register, $dst$$Register); - %} - ins_pipe(ialu_reg); -%} - - -// ============================================================================ -//------------Bytes reverse-------------------------------------------------- - -instruct bytes_reverse_int(iRegI dst, stackSlotI src) %{ - match(Set dst (ReverseBytesI src)); - - // Op cost is artificially doubled to make sure that load or store - // instructions are preferred over this one which requires a spill - // onto a stack slot. - ins_cost(2*DEFAULT_COST + MEMORY_REF_COST); - format %{ "LDUWA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ set($src$$disp + STACK_BIAS, O7); - __ lduwa($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe( iload_mem ); -%} - -instruct bytes_reverse_long(iRegL dst, stackSlotL src) %{ - match(Set dst (ReverseBytesL src)); - - // Op cost is artificially doubled to make sure that load or store - // instructions are preferred over this one which requires a spill - // onto a stack slot. - ins_cost(2*DEFAULT_COST + MEMORY_REF_COST); - format %{ "LDXA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ set($src$$disp + STACK_BIAS, O7); - __ ldxa($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe( iload_mem ); -%} - -instruct bytes_reverse_unsigned_short(iRegI dst, stackSlotI src) %{ - match(Set dst (ReverseBytesUS src)); - - // Op cost is artificially doubled to make sure that load or store - // instructions are preferred over this one which requires a spill - // onto a stack slot. - ins_cost(2*DEFAULT_COST + MEMORY_REF_COST); - format %{ "LDUHA $src, $dst\t!asi=primary_little\n\t" %} - - ins_encode %{ - // the value was spilled as an int so bias the load - __ set($src$$disp + STACK_BIAS + 2, O7); - __ lduha($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe( iload_mem ); -%} - -instruct bytes_reverse_short(iRegI dst, stackSlotI src) %{ - match(Set dst (ReverseBytesS src)); - - // Op cost is artificially doubled to make sure that load or store - // instructions are preferred over this one which requires a spill - // onto a stack slot. - ins_cost(2*DEFAULT_COST + MEMORY_REF_COST); - format %{ "LDSHA $src, $dst\t!asi=primary_little\n\t" %} - - ins_encode %{ - // the value was spilled as an int so bias the load - __ set($src$$disp + STACK_BIAS + 2, O7); - __ ldsha($src$$base$$Register, O7, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe( iload_mem ); -%} - -// Load Integer reversed byte order -instruct loadI_reversed(iRegI dst, indIndexMemory src) %{ - match(Set dst (ReverseBytesI (LoadI src))); - - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(4); - format %{ "LDUWA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ lduwa($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load Long - aligned and reversed -instruct loadL_reversed(iRegL dst, indIndexMemory src) %{ - match(Set dst (ReverseBytesL (LoadL src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "LDXA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ ldxa($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load unsigned short / char reversed byte order -instruct loadUS_reversed(iRegI dst, indIndexMemory src) %{ - match(Set dst (ReverseBytesUS (LoadUS src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "LDUHA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ lduha($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Load short reversed byte order -instruct loadS_reversed(iRegI dst, indIndexMemory src) %{ - match(Set dst (ReverseBytesS (LoadS src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "LDSHA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ ldsha($src$$base$$Register, $src$$index$$Register, Assembler::ASI_PRIMARY_LITTLE, $dst$$Register); - %} - ins_pipe(iload_mem); -%} - -// Store Integer reversed byte order -instruct storeI_reversed(indIndexMemory dst, iRegI src) %{ - match(Set dst (StoreI dst (ReverseBytesI src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STWA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ stwa($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE); - %} - ins_pipe(istore_mem_reg); -%} - -// Store Long reversed byte order -instruct storeL_reversed(indIndexMemory dst, iRegL src) %{ - match(Set dst (StoreL dst (ReverseBytesL src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STXA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ stxa($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE); - %} - ins_pipe(istore_mem_reg); -%} - -// Store unsighed short/char reversed byte order -instruct storeUS_reversed(indIndexMemory dst, iRegI src) %{ - match(Set dst (StoreC dst (ReverseBytesUS src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STHA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ stha($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE); - %} - ins_pipe(istore_mem_reg); -%} - -// Store short reversed byte order -instruct storeS_reversed(indIndexMemory dst, iRegI src) %{ - match(Set dst (StoreC dst (ReverseBytesS src))); - - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STHA $src, $dst\t!asi=primary_little" %} - - ins_encode %{ - __ stha($src$$Register, $dst$$base$$Register, $dst$$index$$Register, Assembler::ASI_PRIMARY_LITTLE); - %} - ins_pipe(istore_mem_reg); -%} - -// ====================VECTOR INSTRUCTIONS===================================== - -// Load Aligned Packed values into a Double Register -instruct loadV8(regD dst, memory mem) %{ - predicate(n->as_LoadVector()->memory_size() == 8); - match(Set dst (LoadVector mem)); - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "LDDF $mem,$dst\t! load vector (8 bytes)" %} - ins_encode %{ - __ ldf(FloatRegisterImpl::D, $mem$$Address, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(floadD_mem); -%} - -// Store Vector in Double register to memory -instruct storeV8(memory mem, regD src) %{ - predicate(n->as_StoreVector()->memory_size() == 8); - match(Set mem (StoreVector mem src)); - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STDF $src,$mem\t! store vector (8 bytes)" %} - ins_encode %{ - __ stf(FloatRegisterImpl::D, as_DoubleFloatRegister($src$$reg), $mem$$Address); - %} - ins_pipe(fstoreD_mem_reg); -%} - -// Store Zero into vector in memory -instruct storeV8B_zero(memory mem, immI0 zero) %{ - predicate(n->as_StoreVector()->memory_size() == 8); - match(Set mem (StoreVector mem (ReplicateB zero))); - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STX $zero,$mem\t! store zero vector (8 bytes)" %} - ins_encode %{ - __ stx(G0, $mem$$Address); - %} - ins_pipe(fstoreD_mem_zero); -%} - -instruct storeV4S_zero(memory mem, immI0 zero) %{ - predicate(n->as_StoreVector()->memory_size() == 8); - match(Set mem (StoreVector mem (ReplicateS zero))); - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STX $zero,$mem\t! store zero vector (4 shorts)" %} - ins_encode %{ - __ stx(G0, $mem$$Address); - %} - ins_pipe(fstoreD_mem_zero); -%} - -instruct storeV2I_zero(memory mem, immI0 zero) %{ - predicate(n->as_StoreVector()->memory_size() == 8); - match(Set mem (StoreVector mem (ReplicateI zero))); - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STX $zero,$mem\t! store zero vector (2 ints)" %} - ins_encode %{ - __ stx(G0, $mem$$Address); - %} - ins_pipe(fstoreD_mem_zero); -%} - -instruct storeV2F_zero(memory mem, immF0 zero) %{ - predicate(n->as_StoreVector()->memory_size() == 8); - match(Set mem (StoreVector mem (ReplicateF zero))); - ins_cost(MEMORY_REF_COST); - size(4); - format %{ "STX $zero,$mem\t! store zero vector (2 floats)" %} - ins_encode %{ - __ stx(G0, $mem$$Address); - %} - ins_pipe(fstoreD_mem_zero); -%} - -// Replicate scalar to packed byte values into Double register -instruct Repl8B_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{ - predicate(n->as_Vector()->length() == 8 && UseVIS >= 3); - match(Set dst (ReplicateB src)); - effect(DEF dst, USE src, TEMP tmp, KILL tmp2); - format %{ "SLLX $src,56,$tmp\n\t" - "SRLX $tmp, 8,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\n\t" - "SRLX $tmp,16,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\n\t" - "SRLX $tmp,32,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\t! replicate8B\n\t" - "MOVXTOD $tmp,$dst\t! MoveL2D" %} - ins_encode %{ - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - Register Rtmp2 = $tmp2$$Register; - __ sllx(Rsrc, 56, Rtmp); - __ srlx(Rtmp, 8, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ srlx(Rtmp, 16, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ srlx(Rtmp, 32, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(ialu_reg); -%} - -// Replicate scalar to packed byte values into Double stack -instruct Repl8B_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{ - predicate(n->as_Vector()->length() == 8 && UseVIS < 3); - match(Set dst (ReplicateB src)); - effect(DEF dst, USE src, TEMP tmp, KILL tmp2); - format %{ "SLLX $src,56,$tmp\n\t" - "SRLX $tmp, 8,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\n\t" - "SRLX $tmp,16,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\n\t" - "SRLX $tmp,32,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\t! replicate8B\n\t" - "STX $tmp,$dst\t! regL to stkD" %} - ins_encode %{ - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - Register Rtmp2 = $tmp2$$Register; - __ sllx(Rsrc, 56, Rtmp); - __ srlx(Rtmp, 8, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ srlx(Rtmp, 16, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ srlx(Rtmp, 32, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ set ($dst$$disp + STACK_BIAS, Rtmp2); - __ stx (Rtmp, Rtmp2, $dst$$base$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Replicate scalar constant to packed byte values in Double register -instruct Repl8B_immI(regD dst, immI13 con, o7RegI tmp) %{ - predicate(n->as_Vector()->length() == 8); - match(Set dst (ReplicateB con)); - effect(KILL tmp); - format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %} - ins_encode %{ - // XXX This is a quick fix for 6833573. - //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister); - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 8, 1)), $tmp$$Register); - __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(loadConFD); -%} - -// Replicate scalar to packed char/short values into Double register -instruct Repl4S_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{ - predicate(n->as_Vector()->length() == 4 && UseVIS >= 3); - match(Set dst (ReplicateS src)); - effect(DEF dst, USE src, TEMP tmp, KILL tmp2); - format %{ "SLLX $src,48,$tmp\n\t" - "SRLX $tmp,16,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\n\t" - "SRLX $tmp,32,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\t! replicate4S\n\t" - "MOVXTOD $tmp,$dst\t! MoveL2D" %} - ins_encode %{ - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - Register Rtmp2 = $tmp2$$Register; - __ sllx(Rsrc, 48, Rtmp); - __ srlx(Rtmp, 16, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ srlx(Rtmp, 32, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(ialu_reg); -%} - -// Replicate scalar to packed char/short values into Double stack -instruct Repl4S_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{ - predicate(n->as_Vector()->length() == 4 && UseVIS < 3); - match(Set dst (ReplicateS src)); - effect(DEF dst, USE src, TEMP tmp, KILL tmp2); - format %{ "SLLX $src,48,$tmp\n\t" - "SRLX $tmp,16,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\n\t" - "SRLX $tmp,32,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\t! replicate4S\n\t" - "STX $tmp,$dst\t! regL to stkD" %} - ins_encode %{ - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - Register Rtmp2 = $tmp2$$Register; - __ sllx(Rsrc, 48, Rtmp); - __ srlx(Rtmp, 16, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ srlx(Rtmp, 32, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ set ($dst$$disp + STACK_BIAS, Rtmp2); - __ stx (Rtmp, Rtmp2, $dst$$base$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Replicate scalar constant to packed char/short values in Double register -instruct Repl4S_immI(regD dst, immI con, o7RegI tmp) %{ - predicate(n->as_Vector()->length() == 4); - match(Set dst (ReplicateS con)); - effect(KILL tmp); - format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %} - ins_encode %{ - // XXX This is a quick fix for 6833573. - //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister); - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register); - __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(loadConFD); -%} - -// Replicate scalar to packed int values into Double register -instruct Repl2I_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{ - predicate(n->as_Vector()->length() == 2 && UseVIS >= 3); - match(Set dst (ReplicateI src)); - effect(DEF dst, USE src, TEMP tmp, KILL tmp2); - format %{ "SLLX $src,32,$tmp\n\t" - "SRLX $tmp,32,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\t! replicate2I\n\t" - "MOVXTOD $tmp,$dst\t! MoveL2D" %} - ins_encode %{ - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - Register Rtmp2 = $tmp2$$Register; - __ sllx(Rsrc, 32, Rtmp); - __ srlx(Rtmp, 32, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(ialu_reg); -%} - -// Replicate scalar to packed int values into Double stack -instruct Repl2I_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{ - predicate(n->as_Vector()->length() == 2 && UseVIS < 3); - match(Set dst (ReplicateI src)); - effect(DEF dst, USE src, TEMP tmp, KILL tmp2); - format %{ "SLLX $src,32,$tmp\n\t" - "SRLX $tmp,32,$tmp2\n\t" - "OR $tmp,$tmp2,$tmp\t! replicate2I\n\t" - "STX $tmp,$dst\t! regL to stkD" %} - ins_encode %{ - Register Rsrc = $src$$Register; - Register Rtmp = $tmp$$Register; - Register Rtmp2 = $tmp2$$Register; - __ sllx(Rsrc, 32, Rtmp); - __ srlx(Rtmp, 32, Rtmp2); - __ or3 (Rtmp, Rtmp2, Rtmp); - __ set ($dst$$disp + STACK_BIAS, Rtmp2); - __ stx (Rtmp, Rtmp2, $dst$$base$$Register); - %} - ins_pipe(ialu_reg); -%} - -// Replicate scalar zero constant to packed int values in Double register -instruct Repl2I_immI(regD dst, immI con, o7RegI tmp) %{ - predicate(n->as_Vector()->length() == 2); - match(Set dst (ReplicateI con)); - effect(KILL tmp); - format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %} - ins_encode %{ - // XXX This is a quick fix for 6833573. - //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister); - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 2, 4)), $tmp$$Register); - __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(loadConFD); -%} - -// Replicate scalar to packed float values into Double stack -instruct Repl2F_stk(stackSlotD dst, regF src) %{ - predicate(n->as_Vector()->length() == 2); - match(Set dst (ReplicateF src)); - ins_cost(MEMORY_REF_COST*2); - format %{ "STF $src,$dst.hi\t! packed2F\n\t" - "STF $src,$dst.lo" %} - opcode(Assembler::stf_op3); - ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, src)); - ins_pipe(fstoreF_stk_reg); -%} - -// Replicate scalar zero constant to packed float values in Double register -instruct Repl2F_immF(regD dst, immF con, o7RegI tmp) %{ - predicate(n->as_Vector()->length() == 2); - match(Set dst (ReplicateF con)); - effect(KILL tmp); - format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2F($con)" %} - ins_encode %{ - // XXX This is a quick fix for 6833573. - //__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immF($con$$constant)), $dst$$FloatRegister); - RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immF($con$$constant)), $tmp$$Register); - __ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg)); - %} - ins_pipe(loadConFD); -%} - -//----------PEEPHOLE RULES----------------------------------------------------- -// These must follow all instruction definitions as they use the names -// defined in the instructions definitions. -// -// peepmatch ( root_instr_name [preceding_instruction]* ); -// -// peepconstraint %{ -// (instruction_number.operand_name relational_op instruction_number.operand_name -// [, ...] ); -// // instruction numbers are zero-based using left to right order in peepmatch -// -// peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); -// // provide an instruction_number.operand_name for each operand that appears -// // in the replacement instruction's match rule -// -// ---------VM FLAGS--------------------------------------------------------- -// -// All peephole optimizations can be turned off using -XX:-OptoPeephole -// -// Each peephole rule is given an identifying number starting with zero and -// increasing by one in the order seen by the parser. An individual peephole -// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=# -// on the command-line. -// -// ---------CURRENT LIMITATIONS---------------------------------------------- -// -// Only match adjacent instructions in same basic block -// Only equality constraints -// Only constraints between operands, not (0.dest_reg == EAX_enc) -// Only one replacement instruction -// -// ---------EXAMPLE---------------------------------------------------------- -// -// // pertinent parts of existing instructions in architecture description -// instruct movI(eRegI dst, eRegI src) %{ -// match(Set dst (CopyI src)); -// %} -// -// instruct incI_eReg(eRegI dst, immI1 src, eFlagsReg cr) %{ -// match(Set dst (AddI dst src)); -// effect(KILL cr); -// %} -// -// // Change (inc mov) to lea -// peephole %{ -// // increment preceeded by register-register move -// peepmatch ( incI_eReg movI ); -// // require that the destination register of the increment -// // match the destination register of the move -// peepconstraint ( 0.dst == 1.dst ); -// // construct a replacement instruction that sets -// // the destination to ( move's source register + one ) -// peepreplace ( incI_eReg_immI1( 0.dst 1.src 0.src ) ); -// %} -// - -// // Change load of spilled value to only a spill -// instruct storeI(memory mem, eRegI src) %{ -// match(Set mem (StoreI mem src)); -// %} -// -// instruct loadI(eRegI dst, memory mem) %{ -// match(Set dst (LoadI mem)); -// %} -// -// peephole %{ -// peepmatch ( loadI storeI ); -// peepconstraint ( 1.src == 0.dst, 1.mem == 0.mem ); -// peepreplace ( storeI( 1.mem 1.mem 1.src ) ); -// %} - -//----------SMARTSPILL RULES--------------------------------------------------- -// These must follow all instruction definitions as they use the names -// defined in the instructions definitions. -// -// SPARC will probably not have any of these rules due to RISC instruction set. - -//----------PIPELINE----------------------------------------------------------- -// Rules which define the behavior of the target architectures pipeline. diff --git a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp +++ /dev/null @@ -1,5875 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetAssembler.hpp" -#include "interpreter/interpreter.hpp" -#include "nativeInst_sparc.hpp" -#include "oops/instanceOop.hpp" -#include "oops/method.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/oop.inline.hpp" -#include "prims/methodHandles.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubCodeGenerator.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/thread.inline.hpp" -#ifdef COMPILER2 -#include "opto/runtime.hpp" -#endif - -// Declaration and definition of StubGenerator (no .hpp file). -// For a more detailed description of the stub routine structure -// see the comment in stubRoutines.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 ":") - -// Note: The register L7 is used as L7_thread_cache, and may not be used -// any other way within this module. - -static const Register& Lstub_temp = L2; - -// ------------------------------------------------------------------------------------------------------------------------- -// Stub Code definitions - -class StubGenerator: public StubCodeGenerator { - private: - -#ifdef PRODUCT -#define inc_counter_np(a,b,c) -#else -#define inc_counter_np(counter, t1, t2) \ - BLOCK_COMMENT("inc_counter " #counter); \ - __ inc_counter(&counter, t1, t2); -#endif - - //---------------------------------------------------------------------------------------------------- - // Call stubs are used to call Java from C - - address generate_call_stub(address& return_pc) { - StubCodeMark mark(this, "StubRoutines", "call_stub"); - address start = __ pc(); - - // Incoming arguments: - // - // o0 : call wrapper address - // o1 : result (address) - // o2 : result type - // o3 : method - // o4 : (interpreter) entry point - // o5 : parameters (address) - // [sp + 0x5c]: parameter size (in words) - // [sp + 0x60]: thread - // - // +---------------+ <--- sp + 0 - // | | - // . reg save area . - // | | - // +---------------+ <--- sp + 0x40 - // | | - // . extra 7 slots . - // | | - // +---------------+ <--- sp + 0x5c - // | param. size | - // +---------------+ <--- sp + 0x60 - // | thread | - // +---------------+ - // | | - - // note: if the link argument position changes, adjust - // the code in frame::entry_frame_call_wrapper() - - const Argument link = Argument(0, false); // used only for GC - const Argument result = Argument(1, false); - const Argument result_type = Argument(2, false); - const Argument method = Argument(3, false); - const Argument entry_point = Argument(4, false); - const Argument parameters = Argument(5, false); - const Argument parameter_size = Argument(6, false); - const Argument thread = Argument(7, false); - - // setup thread register - __ ld_ptr(thread.as_address(), G2_thread); - __ reinit_heapbase(); - -#ifdef ASSERT - // make sure we have no pending exceptions - { const Register t = G3_scratch; - Label L; - __ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), t); - __ br_null_short(t, Assembler::pt, L); - __ stop("StubRoutines::call_stub: entered with pending exception"); - __ bind(L); - } -#endif - - // create activation frame & allocate space for parameters - { const Register t = G3_scratch; - __ ld_ptr(parameter_size.as_address(), t); // get parameter size (in words) - __ add(t, frame::memory_parameter_word_sp_offset, t); // add space for save area (in words) - __ round_to(t, WordsPerLong); // make sure it is multiple of 2 (in words) - __ sll(t, Interpreter::logStackElementSize, t); // compute number of bytes - __ neg(t); // negate so it can be used with save - __ save(SP, t, SP); // setup new frame - } - - // +---------------+ <--- sp + 0 - // | | - // . reg save area . - // | | - // +---------------+ <--- sp + 0x40 - // | | - // . extra 7 slots . - // | | - // +---------------+ <--- sp + 0x5c - // | empty slot | (only if parameter size is even) - // +---------------+ - // | | - // . parameters . - // | | - // +---------------+ <--- fp + 0 - // | | - // . reg save area . - // | | - // +---------------+ <--- fp + 0x40 - // | | - // . extra 7 slots . - // | | - // +---------------+ <--- fp + 0x5c - // | param. size | - // +---------------+ <--- fp + 0x60 - // | thread | - // +---------------+ - // | | - - // pass parameters if any - BLOCK_COMMENT("pass parameters if any"); - { const Register src = parameters.as_in().as_register(); - const Register dst = Lentry_args; - const Register tmp = G3_scratch; - const Register cnt = G4_scratch; - - // test if any parameters & setup of Lentry_args - Label exit; - __ ld_ptr(parameter_size.as_in().as_address(), cnt); // parameter counter - __ add( FP, STACK_BIAS, dst ); - __ cmp_zero_and_br(Assembler::zero, cnt, exit); - __ delayed()->sub(dst, BytesPerWord, dst); // setup Lentry_args - - // copy parameters if any - Label loop; - __ BIND(loop); - // Store parameter value - __ ld_ptr(src, 0, tmp); - __ add(src, BytesPerWord, src); - __ st_ptr(tmp, dst, 0); - __ deccc(cnt); - __ br(Assembler::greater, false, Assembler::pt, loop); - __ delayed()->sub(dst, Interpreter::stackElementSize, dst); - - // done - __ BIND(exit); - } - - // setup parameters, method & call Java function -#ifdef ASSERT - // layout_activation_impl checks it's notion of saved SP against - // this register, so if this changes update it as well. - const Register saved_SP = Lscratch; - __ mov(SP, saved_SP); // keep track of SP before call -#endif - - // setup parameters - const Register t = G3_scratch; - __ ld_ptr(parameter_size.as_in().as_address(), t); // get parameter size (in words) - __ sll(t, Interpreter::logStackElementSize, t); // compute number of bytes - __ sub(FP, t, Gargs); // setup parameter pointer - __ add( Gargs, STACK_BIAS, Gargs ); // Account for LP64 stack bias - __ mov(SP, O5_savedSP); - - - // do the call - // - // the following register must be setup: - // - // G2_thread - // G5_method - // Gargs - BLOCK_COMMENT("call Java function"); - __ jmpl(entry_point.as_in().as_register(), G0, O7); - __ delayed()->mov(method.as_in().as_register(), G5_method); // setup method - - BLOCK_COMMENT("call_stub_return_address:"); - return_pc = __ pc(); - - // The callee, if it wasn't interpreted, can return with SP changed so - // we can no longer assert of change of SP. - - // store result depending on type - // (everything that is not T_OBJECT, T_LONG, T_FLOAT, or T_DOUBLE - // is treated as T_INT) - { const Register addr = result .as_in().as_register(); - const Register type = result_type.as_in().as_register(); - Label is_long, is_float, is_double, is_object, exit; - __ cmp(type, T_OBJECT); __ br(Assembler::equal, false, Assembler::pn, is_object); - __ delayed()->cmp(type, T_FLOAT); __ br(Assembler::equal, false, Assembler::pn, is_float); - __ delayed()->cmp(type, T_DOUBLE); __ br(Assembler::equal, false, Assembler::pn, is_double); - __ delayed()->cmp(type, T_LONG); __ br(Assembler::equal, false, Assembler::pn, is_long); - __ delayed()->nop(); - - // store int result - __ st(O0, addr, G0); - - __ BIND(exit); - __ ret(); - __ delayed()->restore(); - - __ BIND(is_object); - __ ba(exit); - __ delayed()->st_ptr(O0, addr, G0); - - __ BIND(is_float); - __ ba(exit); - __ delayed()->stf(FloatRegisterImpl::S, F0, addr, G0); - - __ BIND(is_double); - __ ba(exit); - __ delayed()->stf(FloatRegisterImpl::D, F0, addr, G0); - - __ BIND(is_long); - __ ba(exit); - __ delayed()->st_long(O0, addr, G0); // store entire long - } - return start; - } - - - //---------------------------------------------------------------------------------------------------- - // Return point for a Java call if there's an exception thrown in Java code. - // The exception is caught and transformed into a pending exception stored in - // JavaThread that can be tested from within the VM. - // - // Oexception: exception oop - - address generate_catch_exception() { - StubCodeMark mark(this, "StubRoutines", "catch_exception"); - - address start = __ pc(); - // verify that thread corresponds - __ verify_thread(); - - const Register& temp_reg = Gtemp; - Address pending_exception_addr (G2_thread, Thread::pending_exception_offset()); - Address exception_file_offset_addr(G2_thread, Thread::exception_file_offset ()); - Address exception_line_offset_addr(G2_thread, Thread::exception_line_offset ()); - - // set pending exception - __ verify_oop(Oexception); - __ st_ptr(Oexception, pending_exception_addr); - __ set((intptr_t)__FILE__, temp_reg); - __ st_ptr(temp_reg, exception_file_offset_addr); - __ set((intptr_t)__LINE__, temp_reg); - __ st(temp_reg, exception_line_offset_addr); - - // complete return to VM - assert(StubRoutines::_call_stub_return_address != NULL, "must have been generated before"); - - AddressLiteral stub_ret(StubRoutines::_call_stub_return_address); - __ jump_to(stub_ret, temp_reg); - __ delayed()->nop(); - - return start; - } - - - //---------------------------------------------------------------------------------------------------- - // Continuation point for runtime calls returning with a pending exception - // The pending exception check happened in the runtime or native call stub - // The pending exception in Thread is converted into a Java-level exception - // - // Contract with Java-level exception handler: O0 = exception - // O1 = throwing pc - - address generate_forward_exception() { - StubCodeMark mark(this, "StubRoutines", "forward_exception"); - address start = __ pc(); - - // Upon entry, O7 has the return address returning into Java - // (interpreted or compiled) code; i.e. the return address - // becomes the throwing pc. - - const Register& handler_reg = Gtemp; - - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - -#ifdef ASSERT - // make sure that this code is only executed if there is a pending exception - { Label L; - __ ld_ptr(exception_addr, Gtemp); - __ br_notnull_short(Gtemp, Assembler::pt, L); - __ stop("StubRoutines::forward exception: no pending exception (1)"); - __ bind(L); - } -#endif - - // compute exception handler into handler_reg - __ get_thread(); - __ ld_ptr(exception_addr, Oexception); - __ verify_oop(Oexception); - __ save_frame(0); // compensates for compiler weakness - __ add(O7->after_save(), frame::pc_return_offset, Lscratch); // save the issuing PC - BLOCK_COMMENT("call exception_handler_for_return_address"); - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), G2_thread, Lscratch); - __ mov(O0, handler_reg); - __ restore(); // compensates for compiler weakness - - __ ld_ptr(exception_addr, Oexception); - __ add(O7, frame::pc_return_offset, Oissuing_pc); // save the issuing PC - -#ifdef ASSERT - // make sure exception is set - { Label L; - __ br_notnull_short(Oexception, Assembler::pt, L); - __ stop("StubRoutines::forward exception: no pending exception (2)"); - __ bind(L); - } -#endif - // jump to exception handler - __ jmp(handler_reg, 0); - // clear pending exception - __ delayed()->st_ptr(G0, exception_addr); - - return start; - } - - // Safefetch stubs. - void generate_safefetch(const char* name, int size, address* entry, - address* fault_pc, address* continuation_pc) { - // safefetch signatures: - // int SafeFetch32(int* adr, int errValue); - // intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue); - // - // arguments: - // o0 = adr - // o1 = errValue - // - // result: - // o0 = *adr or errValue - - StubCodeMark mark(this, "StubRoutines", name); - - // Entry point, pc or function descriptor. - __ align(CodeEntryAlignment); - *entry = __ pc(); - - __ mov(O0, G1); // g1 = o0 - __ mov(O1, O0); // o0 = o1 - // Load *adr into c_rarg1, may fault. - *fault_pc = __ pc(); - switch (size) { - case 4: - // int32_t - __ ldsw(G1, 0, O0); // o0 = [g1] - break; - case 8: - // int64_t - __ ldx(G1, 0, O0); // o0 = [g1] - break; - default: - ShouldNotReachHere(); - } - - // return errValue or *adr - *continuation_pc = __ pc(); - // By convention with the trap handler we ensure there is a non-CTI - // instruction in the trap shadow. - __ nop(); - __ retl(); - __ delayed()->nop(); - } - - //------------------------------------------------------------------------------------------------------------------------ - // Continuation point for throwing of implicit exceptions that are not handled in - // the current activation. Fabricates an exception oop and initiates normal - // exception dispatching in this frame. Only callee-saved registers are preserved - // (through the normal register window / RegisterMap handling). - // If the compiler needs all registers to be preserved between the fault - // point and the exception handler then it must assume responsibility for that in - // AbstractCompiler::continuation_for_implicit_null_exception or - // continuation_for_implicit_division_by_zero_exception. All other implicit - // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are - // either at call sites or otherwise assume that stack unwinding will be initiated, - // so caller saved registers were assumed volatile in the compiler. - - // Note that we generate only this stub into a RuntimeStub, because it needs to be - // properly traversed and ignored during GC, so we change the meaning of the "__" - // macro within this method. -#undef __ -#define __ masm-> - - address generate_throw_exception(const char* name, address runtime_entry, - Register arg1 = noreg, Register arg2 = noreg) { -#ifdef ASSERT - int insts_size = VerifyThread ? 1 * K : 600; -#else - int insts_size = VerifyThread ? 1 * K : 256; -#endif /* ASSERT */ - int locs_size = 32; - - CodeBuffer code(name, insts_size, locs_size); - MacroAssembler* masm = new MacroAssembler(&code); - - __ verify_thread(); - - // This is an inlined and slightly modified version of call_VM - // which has the ability to fetch the return PC out of thread-local storage - __ assert_not_delayed(); - - // Note that we always push a frame because on the SPARC - // architecture, for all of our implicit exception kinds at call - // sites, the implicit exception is taken before the callee frame - // is pushed. - __ save_frame(0); - - int frame_complete = __ offset(); - - // Note that we always have a runtime stub frame on the top of stack by this point - Register last_java_sp = SP; - // 64-bit last_java_sp is biased! - __ set_last_Java_frame(last_java_sp, G0); - if (VerifyThread) __ mov(G2_thread, O0); // about to be smashed; pass early - __ save_thread(noreg); - if (arg1 != noreg) { - assert(arg2 != O1, "clobbered"); - __ mov(arg1, O1); - } - if (arg2 != noreg) { - __ mov(arg2, O2); - } - // do the call - BLOCK_COMMENT("call runtime_entry"); - __ call(runtime_entry, relocInfo::runtime_call_type); - if (!VerifyThread) - __ delayed()->mov(G2_thread, O0); // pass thread as first argument - else - __ delayed()->nop(); // (thread already passed) - __ restore_thread(noreg); - __ reset_last_Java_frame(); - - // check for pending exceptions. use Gtemp as scratch register. -#ifdef ASSERT - Label L; - - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - Register scratch_reg = Gtemp; - __ ld_ptr(exception_addr, scratch_reg); - __ br_notnull_short(scratch_reg, Assembler::pt, L); - __ should_not_reach_here(); - __ bind(L); -#endif // ASSERT - BLOCK_COMMENT("call forward_exception_entry"); - __ call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); - // we use O7 linkage so that forward_exception_entry has the issuing PC - __ delayed()->restore(); - - RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, frame_complete, masm->total_frame_size_in_bytes(0), NULL, false); - return stub->entry_point(); - } - -#undef __ -#define __ _masm-> - - - // Generate a routine that sets all the registers so we - // can tell if the stop routine prints them correctly. - address generate_test_stop() { - StubCodeMark mark(this, "StubRoutines", "test_stop"); - address start = __ pc(); - - int i; - - __ save_frame(0); - - static jfloat zero = 0.0, one = 1.0; - - // put addr in L0, then load through L0 to F0 - __ set((intptr_t)&zero, L0); __ ldf( FloatRegisterImpl::S, L0, 0, F0); - __ set((intptr_t)&one, L0); __ ldf( FloatRegisterImpl::S, L0, 0, F1); // 1.0 to F1 - - // use add to put 2..18 in F2..F18 - for ( i = 2; i <= 18; ++i ) { - __ fadd( FloatRegisterImpl::S, F1, as_FloatRegister(i-1), as_FloatRegister(i)); - } - - // Now put double 2 in F16, double 18 in F18 - __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, F2, F16 ); - __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, F18, F18 ); - - // use add to put 20..32 in F20..F32 - for (i = 20; i < 32; i += 2) { - __ fadd( FloatRegisterImpl::D, F16, as_FloatRegister(i-2), as_FloatRegister(i)); - } - - // put 0..7 in i's, 8..15 in l's, 16..23 in o's, 24..31 in g's - for ( i = 0; i < 8; ++i ) { - if (i < 6) { - __ set( i, as_iRegister(i)); - __ set(16 + i, as_oRegister(i)); - __ set(24 + i, as_gRegister(i)); - } - __ set( 8 + i, as_lRegister(i)); - } - - __ stop("testing stop"); - - - __ ret(); - __ delayed()->restore(); - - return start; - } - - - address generate_stop_subroutine() { - StubCodeMark mark(this, "StubRoutines", "stop_subroutine"); - address start = __ pc(); - - __ stop_subroutine(); - - return start; - } - - address generate_flush_callers_register_windows() { - StubCodeMark mark(this, "StubRoutines", "flush_callers_register_windows"); - address start = __ pc(); - - __ flushw(); - __ retl(false); - __ delayed()->add( FP, STACK_BIAS, O0 ); - // The returned value must be a stack pointer whose register save area - // is flushed, and will stay flushed while the caller executes. - - return start; - } - - // Implementation of jint atomic_xchg(jint exchange_value, volatile jint* dest) - // used by Atomic::xchg(volatile jint* dest, jint exchange_value) - // - // Arguments: - // - // exchange_value: O0 - // dest: O1 - // - // Results: - // - // O0: the value previously stored in dest - // - address generate_atomic_xchg() { - StubCodeMark mark(this, "StubRoutines", "atomic_xchg"); - address start = __ pc(); - - if (UseCASForSwap) { - // Use CAS instead of swap, just in case the MP hardware - // prefers to work with just one kind of synch. instruction. - Label retry; - __ BIND(retry); - __ mov(O0, O3); // scratch copy of exchange value - __ ld(O1, 0, O2); // observe the previous value - // try to replace O2 with O3 - __ cas(O1, O2, O3); - __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pn, retry); - - __ retl(false); - __ delayed()->mov(O2, O0); // report previous value to caller - } else { - __ retl(false); - __ delayed()->swap(O1, 0, O0); - } - - return start; - } - - - // Implementation of jint atomic_cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) - // used by Atomic::cmpxchg(volatile jint* dest, jint compare_value, jint exchange_value) - // - // Arguments: - // - // exchange_value: O0 - // dest: O1 - // compare_value: O2 - // - // Results: - // - // O0: the value previously stored in dest - // - address generate_atomic_cmpxchg() { - StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg"); - address start = __ pc(); - - // cmpxchg(dest, compare_value, exchange_value) - __ cas(O1, O2, O0); - __ retl(false); - __ delayed()->nop(); - - return start; - } - - // Implementation of jlong atomic_cmpxchg_long(jlong exchange_value, volatile jlong *dest, jlong compare_value) - // used by Atomic::cmpxchg(volatile jlong *dest, jlong compare_value, jlong exchange_value) - // - // Arguments: - // - // exchange_value: O1:O0 - // dest: O2 - // compare_value: O4:O3 - // - // Results: - // - // O1:O0: the value previously stored in dest - // - // Overwrites: G1,G2,G3 - // - address generate_atomic_cmpxchg_long() { - StubCodeMark mark(this, "StubRoutines", "atomic_cmpxchg_long"); - address start = __ pc(); - - __ sllx(O0, 32, O0); - __ srl(O1, 0, O1); - __ or3(O0,O1,O0); // O0 holds 64-bit value from compare_value - __ sllx(O3, 32, O3); - __ srl(O4, 0, O4); - __ or3(O3,O4,O3); // O3 holds 64-bit value from exchange_value - __ casx(O2, O3, O0); - __ srl(O0, 0, O1); // unpacked return value in O1:O0 - __ retl(false); - __ delayed()->srlx(O0, 32, O0); - - return start; - } - - - // Implementation of jint atomic_add(jint add_value, volatile jint* dest) - // used by Atomic::add(volatile jint* dest, jint add_value) - // - // Arguments: - // - // add_value: O0 (e.g., +1 or -1) - // dest: O1 - // - // Results: - // - // O0: the new value stored in dest - // - // Overwrites: O3 - // - address generate_atomic_add() { - StubCodeMark mark(this, "StubRoutines", "atomic_add"); - address start = __ pc(); - __ BIND(_atomic_add_stub); - - Label(retry); - __ BIND(retry); - - __ lduw(O1, 0, O2); - __ add(O0, O2, O3); - __ cas(O1, O2, O3); - __ cmp_and_br_short(O2, O3, Assembler::notEqual, Assembler::pn, retry); - __ retl(false); - __ delayed()->add(O0, O2, O0); // note that cas made O2==O3 - - return start; - } - Label _atomic_add_stub; // called from other stubs - - - // Support for uint StubRoutine::Sparc::partial_subtype_check( Klass sub, Klass super ); - // Arguments : - // - // ret : O0, returned - // icc/xcc: set as O0 (depending on wordSize) - // sub : O1, argument, not changed - // super: O2, argument, not changed - // raddr: O7, blown by call - address generate_partial_subtype_check() { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "partial_subtype_check"); - address start = __ pc(); - Label miss; - - __ save_frame(0); - Register Rret = I0; - Register Rsub = I1; - Register Rsuper = I2; - - Register L0_ary_len = L0; - Register L1_ary_ptr = L1; - Register L2_super = L2; - Register L3_index = L3; - - __ check_klass_subtype_slow_path(Rsub, Rsuper, - L0, L1, L2, L3, - NULL, &miss); - - // Match falls through here. - __ addcc(G0,0,Rret); // set Z flags, Z result - - __ ret(); // Result in Rret is zero; flags set to Z - __ delayed()->restore(); - - __ BIND(miss); - __ addcc(G0,1,Rret); // set NZ flags, NZ result - - __ ret(); // Result in Rret is != 0; flags set to NZ - __ delayed()->restore(); - - return start; - } - - - // Called from MacroAssembler::verify_oop - // - address generate_verify_oop_subroutine() { - StubCodeMark mark(this, "StubRoutines", "verify_oop_stub"); - - address start = __ pc(); - - __ verify_oop_subroutine(); - - return start; - } - - - // - // Verify that a register contains clean 32-bits positive value - // (high 32-bits are 0) so it could be used in 64-bits shifts (sllx, srax). - // - // Input: - // Rint - 32-bits value - // Rtmp - scratch - // - void assert_clean_int(Register Rint, Register Rtmp) { - #if defined(ASSERT) - __ signx(Rint, Rtmp); - __ cmp(Rint, Rtmp); - __ breakpoint_trap(Assembler::notEqual, Assembler::xcc); - #endif - } - - // - // Generate overlap test for array copy stubs - // - // Input: - // O0 - array1 - // O1 - array2 - // O2 - element count - // - // Kills temps: O3, O4 - // - void array_overlap_test(address no_overlap_target, int log2_elem_size) { - assert(no_overlap_target != NULL, "must be generated"); - array_overlap_test(no_overlap_target, NULL, log2_elem_size); - } - void array_overlap_test(Label& L_no_overlap, int log2_elem_size) { - array_overlap_test(NULL, &L_no_overlap, log2_elem_size); - } - void array_overlap_test(address no_overlap_target, Label* NOLp, int log2_elem_size) { - const Register from = O0; - const Register to = O1; - const Register count = O2; - const Register to_from = O3; // to - from - const Register byte_count = O4; // count << log2_elem_size - - __ subcc(to, from, to_from); - __ sll_ptr(count, log2_elem_size, byte_count); - if (NOLp == NULL) - __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, no_overlap_target); - else - __ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, (*NOLp)); - __ delayed()->cmp(to_from, byte_count); - if (NOLp == NULL) - __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, no_overlap_target); - else - __ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, (*NOLp)); - __ delayed()->nop(); - } - - - // - // Generate main code for disjoint arraycopy - // - typedef void (StubGenerator::*CopyLoopFunc)(Register from, Register to, Register count, int count_dec, - Label& L_loop, bool use_prefetch, bool use_bis); - - void disjoint_copy_core(Register from, Register to, Register count, int log2_elem_size, - int iter_size, StubGenerator::CopyLoopFunc copy_loop_func) { - Label L_copy; - - assert(log2_elem_size <= 3, "the following code should be changed"); - int count_dec = 16>>log2_elem_size; - - int prefetch_dist = MAX2(ArraycopySrcPrefetchDistance, ArraycopyDstPrefetchDistance); - assert(prefetch_dist < 4096, "invalid value"); - prefetch_dist = (prefetch_dist + (iter_size-1)) & (-iter_size); // round up to one iteration copy size - int prefetch_count = (prefetch_dist >> log2_elem_size); // elements count - - if (UseBlockCopy) { - Label L_block_copy, L_block_copy_prefetch, L_skip_block_copy; - - // 64 bytes tail + bytes copied in one loop iteration - int tail_size = 64 + iter_size; - int block_copy_count = (MAX2(tail_size, (int)BlockCopyLowLimit)) >> log2_elem_size; - // Use BIS copy only for big arrays since it requires membar. - __ set(block_copy_count, O4); - __ cmp_and_br_short(count, O4, Assembler::lessUnsigned, Assembler::pt, L_skip_block_copy); - // This code is for disjoint source and destination: - // to <= from || to >= from+count - // but BIS will stomp over 'from' if (to > from-tail_size && to <= from) - __ sub(from, to, O4); - __ srax(O4, 4, O4); // divide by 16 since following short branch have only 5 bits for imm. - __ cmp_and_br_short(O4, (tail_size>>4), Assembler::lessEqualUnsigned, Assembler::pn, L_skip_block_copy); - - __ wrasi(G0, Assembler::ASI_ST_BLKINIT_PRIMARY); - // BIS should not be used to copy tail (64 bytes+iter_size) - // to avoid zeroing of following values. - __ sub(count, (tail_size>>log2_elem_size), count); // count is still positive >= 0 - - if (prefetch_count > 0) { // rounded up to one iteration count - // Do prefetching only if copy size is bigger - // than prefetch distance. - __ set(prefetch_count, O4); - __ cmp_and_brx_short(count, O4, Assembler::less, Assembler::pt, L_block_copy); - __ sub(count, O4, count); - - (this->*copy_loop_func)(from, to, count, count_dec, L_block_copy_prefetch, true, true); - __ set(prefetch_count, O4); - __ add(count, O4, count); - - } // prefetch_count > 0 - - (this->*copy_loop_func)(from, to, count, count_dec, L_block_copy, false, true); - __ add(count, (tail_size>>log2_elem_size), count); // restore count - - __ wrasi(G0, Assembler::ASI_PRIMARY_NOFAULT); - // BIS needs membar. - __ membar(Assembler::StoreLoad); - // Copy tail - __ ba_short(L_copy); - - __ BIND(L_skip_block_copy); - } // UseBlockCopy - - if (prefetch_count > 0) { // rounded up to one iteration count - // Do prefetching only if copy size is bigger - // than prefetch distance. - __ set(prefetch_count, O4); - __ cmp_and_brx_short(count, O4, Assembler::lessUnsigned, Assembler::pt, L_copy); - __ sub(count, O4, count); - - Label L_copy_prefetch; - (this->*copy_loop_func)(from, to, count, count_dec, L_copy_prefetch, true, false); - __ set(prefetch_count, O4); - __ add(count, O4, count); - - } // prefetch_count > 0 - - (this->*copy_loop_func)(from, to, count, count_dec, L_copy, false, false); - } - - - - // - // Helper methods for copy_16_bytes_forward_with_shift() - // - void copy_16_bytes_shift_loop(Register from, Register to, Register count, int count_dec, - Label& L_loop, bool use_prefetch, bool use_bis) { - - const Register left_shift = G1; // left shift bit counter - const Register right_shift = G5; // right shift bit counter - - __ align(OptoLoopAlignment); - __ BIND(L_loop); - if (use_prefetch) { - if (ArraycopySrcPrefetchDistance > 0) { - __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads); - } - if (ArraycopyDstPrefetchDistance > 0) { - __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads); - } - } - __ ldx(from, 0, O4); - __ ldx(from, 8, G4); - __ inc(to, 16); - __ inc(from, 16); - __ deccc(count, count_dec); // Can we do next iteration after this one? - __ srlx(O4, right_shift, G3); - __ bset(G3, O3); - __ sllx(O4, left_shift, O4); - __ srlx(G4, right_shift, G3); - __ bset(G3, O4); - if (use_bis) { - __ stxa(O3, to, -16); - __ stxa(O4, to, -8); - } else { - __ stx(O3, to, -16); - __ stx(O4, to, -8); - } - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); - __ delayed()->sllx(G4, left_shift, O3); - } - - // Copy big chunks forward with shift - // - // Inputs: - // from - source arrays - // to - destination array aligned to 8-bytes - // count - elements count to copy >= the count equivalent to 16 bytes - // count_dec - elements count's decrement equivalent to 16 bytes - // L_copy_bytes - copy exit label - // - void copy_16_bytes_forward_with_shift(Register from, Register to, - Register count, int log2_elem_size, Label& L_copy_bytes) { - Label L_aligned_copy, L_copy_last_bytes; - assert(log2_elem_size <= 3, "the following code should be changed"); - int count_dec = 16>>log2_elem_size; - - // if both arrays have the same alignment mod 8, do 8 bytes aligned copy - __ andcc(from, 7, G1); // misaligned bytes - __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); - __ delayed()->nop(); - - const Register left_shift = G1; // left shift bit counter - const Register right_shift = G5; // right shift bit counter - - __ sll(G1, LogBitsPerByte, left_shift); - __ mov(64, right_shift); - __ sub(right_shift, left_shift, right_shift); - - // - // Load 2 aligned 8-bytes chunks and use one from previous iteration - // to form 2 aligned 8-bytes chunks to store. - // - __ dec(count, count_dec); // Pre-decrement 'count' - __ andn(from, 7, from); // Align address - __ ldx(from, 0, O3); - __ inc(from, 8); - __ sllx(O3, left_shift, O3); - - disjoint_copy_core(from, to, count, log2_elem_size, 16, &StubGenerator::copy_16_bytes_shift_loop); - - __ inccc(count, count_dec>>1 ); // + 8 bytes - __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes); - __ delayed()->inc(count, count_dec>>1); // restore 'count' - - // copy 8 bytes, part of them already loaded in O3 - __ ldx(from, 0, O4); - __ inc(to, 8); - __ inc(from, 8); - __ srlx(O4, right_shift, G3); - __ bset(O3, G3); - __ stx(G3, to, -8); - - __ BIND(L_copy_last_bytes); - __ srl(right_shift, LogBitsPerByte, right_shift); // misaligned bytes - __ br(Assembler::always, false, Assembler::pt, L_copy_bytes); - __ delayed()->sub(from, right_shift, from); // restore address - - __ BIND(L_aligned_copy); - } - - // Copy big chunks backward with shift - // - // Inputs: - // end_from - source arrays end address - // end_to - destination array end address aligned to 8-bytes - // count - elements count to copy >= the count equivalent to 16 bytes - // count_dec - elements count's decrement equivalent to 16 bytes - // L_aligned_copy - aligned copy exit label - // L_copy_bytes - copy exit label - // - void copy_16_bytes_backward_with_shift(Register end_from, Register end_to, - Register count, int count_dec, - Label& L_aligned_copy, Label& L_copy_bytes) { - Label L_loop, L_copy_last_bytes; - - // if both arrays have the same alignment mod 8, do 8 bytes aligned copy - __ andcc(end_from, 7, G1); // misaligned bytes - __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); - __ delayed()->deccc(count, count_dec); // Pre-decrement 'count' - - const Register left_shift = G1; // left shift bit counter - const Register right_shift = G5; // right shift bit counter - - __ sll(G1, LogBitsPerByte, left_shift); - __ mov(64, right_shift); - __ sub(right_shift, left_shift, right_shift); - - // - // Load 2 aligned 8-bytes chunks and use one from previous iteration - // to form 2 aligned 8-bytes chunks to store. - // - __ andn(end_from, 7, end_from); // Align address - __ ldx(end_from, 0, O3); - __ align(OptoLoopAlignment); - __ BIND(L_loop); - __ ldx(end_from, -8, O4); - __ deccc(count, count_dec); // Can we do next iteration after this one? - __ ldx(end_from, -16, G4); - __ dec(end_to, 16); - __ dec(end_from, 16); - __ srlx(O3, right_shift, O3); - __ sllx(O4, left_shift, G3); - __ bset(G3, O3); - __ stx(O3, end_to, 8); - __ srlx(O4, right_shift, O4); - __ sllx(G4, left_shift, G3); - __ bset(G3, O4); - __ stx(O4, end_to, 0); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); - __ delayed()->mov(G4, O3); - - __ inccc(count, count_dec>>1 ); // + 8 bytes - __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes); - __ delayed()->inc(count, count_dec>>1); // restore 'count' - - // copy 8 bytes, part of them already loaded in O3 - __ ldx(end_from, -8, O4); - __ dec(end_to, 8); - __ dec(end_from, 8); - __ srlx(O3, right_shift, O3); - __ sllx(O4, left_shift, G3); - __ bset(O3, G3); - __ stx(G3, end_to, 0); - - __ BIND(L_copy_last_bytes); - __ srl(left_shift, LogBitsPerByte, left_shift); // misaligned bytes - __ br(Assembler::always, false, Assembler::pt, L_copy_bytes); - __ delayed()->add(end_from, left_shift, end_from); // restore address - } - - address generate_unsafecopy_common_error_exit() { - address start_pc = __ pc(); - if (UseBlockCopy) { - __ wrasi(G0, Assembler::ASI_PRIMARY_NOFAULT); - __ membar(Assembler::StoreLoad); - } - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start_pc; - } - - // - // Generate stub for disjoint byte copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_disjoint_byte_copy(bool aligned, address *entry, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_skip_alignment, L_align; - Label L_copy_byte, L_copy_byte_loop, L_exit; - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register offset = O5; // offset from start of arrays - // O3, O4, G3, G4 are used as temp registers - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, !aligned, false); - - // for short arrays, just do single element copy - __ cmp(count, 23); // 16 + 7 - __ brx(Assembler::less, false, Assembler::pn, L_copy_byte); - __ delayed()->mov(G0, offset); - - if (aligned) { - // 'aligned' == true when it is known statically during compilation - // of this arraycopy call site that both 'from' and 'to' addresses - // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()). - // - // Aligned arrays have 4 bytes alignment in 32-bits VM - // and 8 bytes - in 64-bits VM. So we do it only for 32-bits VM - // - } else { - // copy bytes to align 'to' on 8 byte boundary - __ andcc(to, 7, G1); // misaligned bytes - __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); - __ delayed()->neg(G1); - __ inc(G1, 8); // bytes need to copy to next 8-bytes alignment - __ sub(count, G1, count); - __ BIND(L_align); - __ ldub(from, 0, O3); - __ deccc(G1); - __ inc(from); - __ stb(O3, to, 0); - __ br(Assembler::notZero, false, Assembler::pt, L_align); - __ delayed()->inc(to); - __ BIND(L_skip_alignment); - } - if (!aligned) { - // Copy with shift 16 bytes per iteration if arrays do not have - // the same alignment mod 8, otherwise fall through to the next - // code for aligned copy. - // The compare above (count >= 23) guarantes 'count' >= 16 bytes. - // Also jump over aligned copy after the copy with shift completed. - - copy_16_bytes_forward_with_shift(from, to, count, 0, L_copy_byte); - } - - // Both array are 8 bytes aligned, copy 16 bytes at a time - __ and3(count, 7, G4); // Save count - __ srl(count, 3, count); - generate_disjoint_long_copy_core(aligned); - __ mov(G4, count); // Restore count - - // copy tailing bytes - __ BIND(L_copy_byte); - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit); - __ align(OptoLoopAlignment); - __ BIND(L_copy_byte_loop); - __ ldub(from, offset, O3); - __ deccc(count); - __ stb(O3, to, offset); - __ brx(Assembler::notZero, false, Assembler::pt, L_copy_byte_loop); - __ delayed()->inc(offset); - } - - __ BIND(L_exit); - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Generate stub for conjoint byte copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_conjoint_byte_copy(bool aligned, address nooverlap_target, - address *entry, const char *name) { - // Do reverse copy. - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_skip_alignment, L_align, L_aligned_copy; - Label L_copy_byte, L_copy_byte_loop, L_exit; - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register end_from = from; // source array end address - const Register end_to = to; // destination array end address - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - array_overlap_test(nooverlap_target, 0); - - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, !aligned, false); - - __ add(to, count, end_to); // offset after last copied element - - // for short arrays, just do single element copy - __ cmp(count, 23); // 16 + 7 - __ brx(Assembler::less, false, Assembler::pn, L_copy_byte); - __ delayed()->add(from, count, end_from); - - { - // Align end of arrays since they could be not aligned even - // when arrays itself are aligned. - - // copy bytes to align 'end_to' on 8 byte boundary - __ andcc(end_to, 7, G1); // misaligned bytes - __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); - __ delayed()->nop(); - __ sub(count, G1, count); - __ BIND(L_align); - __ dec(end_from); - __ dec(end_to); - __ ldub(end_from, 0, O3); - __ deccc(G1); - __ brx(Assembler::notZero, false, Assembler::pt, L_align); - __ delayed()->stb(O3, end_to, 0); - __ BIND(L_skip_alignment); - } - if (aligned) { - // Both arrays are aligned to 8-bytes in 64-bits VM. - // The 'count' is decremented in copy_16_bytes_backward_with_shift() - // in unaligned case. - __ dec(count, 16); - } else { - // Copy with shift 16 bytes per iteration if arrays do not have - // the same alignment mod 8, otherwise jump to the next - // code for aligned copy (and substracting 16 from 'count' before jump). - // The compare above (count >= 11) guarantes 'count' >= 16 bytes. - // Also jump over aligned copy after the copy with shift completed. - - copy_16_bytes_backward_with_shift(end_from, end_to, count, 16, - L_aligned_copy, L_copy_byte); - } - // copy 4 elements (16 bytes) at a time - __ align(OptoLoopAlignment); - __ BIND(L_aligned_copy); - __ dec(end_from, 16); - __ ldx(end_from, 8, O3); - __ ldx(end_from, 0, O4); - __ dec(end_to, 16); - __ deccc(count, 16); - __ stx(O3, end_to, 8); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy); - __ delayed()->stx(O4, end_to, 0); - __ inc(count, 16); - - // copy 1 element (2 bytes) at a time - __ BIND(L_copy_byte); - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit); - __ align(OptoLoopAlignment); - __ BIND(L_copy_byte_loop); - __ dec(end_from); - __ dec(end_to); - __ ldub(end_from, 0, O4); - __ deccc(count); - __ brx(Assembler::greater, false, Assembler::pt, L_copy_byte_loop); - __ delayed()->stb(O4, end_to, 0); - } - - __ BIND(L_exit); - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Generate stub for disjoint short copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_disjoint_short_copy(bool aligned, address *entry, const char * name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_skip_alignment, L_skip_alignment2; - Label L_copy_2_bytes, L_copy_2_bytes_loop, L_exit; - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register offset = O5; // offset from start of arrays - // O3, O4, G3, G4 are used as temp registers - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, !aligned, false); - // for short arrays, just do single element copy - __ cmp(count, 11); // 8 + 3 (22 bytes) - __ brx(Assembler::less, false, Assembler::pn, L_copy_2_bytes); - __ delayed()->mov(G0, offset); - - if (aligned) { - // 'aligned' == true when it is known statically during compilation - // of this arraycopy call site that both 'from' and 'to' addresses - // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()). - // - // Aligned arrays have 4 bytes alignment in 32-bits VM - // and 8 bytes - in 64-bits VM. - // - } else { - // copy 1 element if necessary to align 'to' on an 4 bytes - __ andcc(to, 3, G0); - __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); - __ delayed()->lduh(from, 0, O3); - __ inc(from, 2); - __ inc(to, 2); - __ dec(count); - __ sth(O3, to, -2); - __ BIND(L_skip_alignment); - - // copy 2 elements to align 'to' on an 8 byte boundary - __ andcc(to, 7, G0); - __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment2); - __ delayed()->lduh(from, 0, O3); - __ dec(count, 2); - __ lduh(from, 2, O4); - __ inc(from, 4); - __ inc(to, 4); - __ sth(O3, to, -4); - __ sth(O4, to, -2); - __ BIND(L_skip_alignment2); - } - if (!aligned) { - // Copy with shift 16 bytes per iteration if arrays do not have - // the same alignment mod 8, otherwise fall through to the next - // code for aligned copy. - // The compare above (count >= 11) guarantes 'count' >= 16 bytes. - // Also jump over aligned copy after the copy with shift completed. - - copy_16_bytes_forward_with_shift(from, to, count, 1, L_copy_2_bytes); - } - - // Both array are 8 bytes aligned, copy 16 bytes at a time - __ and3(count, 3, G4); // Save - __ srl(count, 2, count); - generate_disjoint_long_copy_core(aligned); - __ mov(G4, count); // restore - - // copy 1 element at a time - __ BIND(L_copy_2_bytes); - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit); - __ align(OptoLoopAlignment); - __ BIND(L_copy_2_bytes_loop); - __ lduh(from, offset, O3); - __ deccc(count); - __ sth(O3, to, offset); - __ brx(Assembler::notZero, false, Assembler::pt, L_copy_2_bytes_loop); - __ delayed()->inc(offset, 2); - } - - __ BIND(L_exit); - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jshort_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Generate stub for disjoint short fill. If "aligned" is true, the - // "to" address is assumed to be heapword aligned. - // - // Arguments for generated stub: - // to: O0 - // value: O1 - // count: O2 treated as signed - // - address generate_fill(BasicType t, bool aligned, const char* name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - const Register to = O0; // source array address - const Register value = O1; // fill value - const Register count = O2; // elements count - // O3 is used as a temp register - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte; - Label L_fill_2_bytes, L_fill_elements, L_fill_32_bytes; - - int shift = -1; - switch (t) { - case T_BYTE: - shift = 2; - break; - case T_SHORT: - shift = 1; - break; - case T_INT: - shift = 0; - break; - default: ShouldNotReachHere(); - } - - BLOCK_COMMENT("Entry:"); - - if (t == T_BYTE) { - // Zero extend value - __ and3(value, 0xff, value); - __ sllx(value, 8, O3); - __ or3(value, O3, value); - } - if (t == T_SHORT) { - // Zero extend value - __ sllx(value, 48, value); - __ srlx(value, 48, value); - } - if (t == T_BYTE || t == T_SHORT) { - __ sllx(value, 16, O3); - __ or3(value, O3, value); - } - - __ cmp(count, 2<andcc(count, 1, G0); - - if (!aligned && (t == T_BYTE || t == T_SHORT)) { - // align source address at 4 bytes address boundary - if (t == T_BYTE) { - // One byte misalignment happens only for byte arrays - __ andcc(to, 1, G0); - __ br(Assembler::zero, false, Assembler::pt, L_skip_align1); - __ delayed()->nop(); - __ stb(value, to, 0); - __ inc(to, 1); - __ dec(count, 1); - __ BIND(L_skip_align1); - } - // Two bytes misalignment happens only for byte and short (char) arrays - __ andcc(to, 2, G0); - __ br(Assembler::zero, false, Assembler::pt, L_skip_align2); - __ delayed()->nop(); - __ sth(value, to, 0); - __ inc(to, 2); - __ dec(count, 1 << (shift - 1)); - __ BIND(L_skip_align2); - } - if (!aligned) { - // align to 8 bytes, we know we are 4 byte aligned to start - __ andcc(to, 7, G0); - __ br(Assembler::zero, false, Assembler::pt, L_fill_32_bytes); - __ delayed()->nop(); - __ stw(value, to, 0); - __ inc(to, 4); - __ dec(count, 1 << shift); - __ BIND(L_fill_32_bytes); - } - - if (t == T_INT) { - // Zero extend value - __ srl(value, 0, value); - } - if (t == T_BYTE || t == T_SHORT || t == T_INT) { - __ sllx(value, 32, O3); - __ or3(value, O3, value); - } - - Label L_check_fill_8_bytes; - // Fill 32-byte chunks - __ subcc(count, 8 << shift, count); - __ brx(Assembler::less, false, Assembler::pt, L_check_fill_8_bytes); - __ delayed()->nop(); - - Label L_fill_32_bytes_loop, L_fill_4_bytes; - __ align(16); - __ BIND(L_fill_32_bytes_loop); - - __ stx(value, to, 0); - __ stx(value, to, 8); - __ stx(value, to, 16); - __ stx(value, to, 24); - - __ subcc(count, 8 << shift, count); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_fill_32_bytes_loop); - __ delayed()->add(to, 32, to); - - __ BIND(L_check_fill_8_bytes); - __ addcc(count, 8 << shift, count); - __ brx(Assembler::zero, false, Assembler::pn, L_exit); - __ delayed()->subcc(count, 1 << (shift + 1), count); - __ brx(Assembler::less, false, Assembler::pn, L_fill_4_bytes); - __ delayed()->andcc(count, 1<add(to, 8, to); - - // fill trailing 4 bytes - __ andcc(count, 1<andcc(count, 1<<(shift-1), G0); - } else { - __ delayed()->nop(); - } - __ stw(value, to, 0); - if (t == T_BYTE || t == T_SHORT) { - __ inc(to, 4); - // fill trailing 2 bytes - __ andcc(count, 1<<(shift-1), G0); // in delay slot of branches - __ BIND(L_fill_2_bytes); - __ brx(Assembler::zero, false, Assembler::pt, L_fill_byte); - __ delayed()->andcc(count, 1, count); - __ sth(value, to, 0); - if (t == T_BYTE) { - __ inc(to, 2); - // fill trailing byte - __ andcc(count, 1, count); // in delay slot of branches - __ BIND(L_fill_byte); - __ brx(Assembler::zero, false, Assembler::pt, L_exit); - __ delayed()->nop(); - __ stb(value, to, 0); - } else { - __ BIND(L_fill_byte); - } - } else { - __ BIND(L_fill_2_bytes); - } - __ BIND(L_exit); - __ retl(); - __ delayed()->nop(); - - // Handle copies less than 8 bytes. Int is handled elsewhere. - if (t == T_BYTE) { - __ BIND(L_fill_elements); - Label L_fill_2, L_fill_4; - // in delay slot __ andcc(count, 1, G0); - __ brx(Assembler::zero, false, Assembler::pt, L_fill_2); - __ delayed()->andcc(count, 2, G0); - __ stb(value, to, 0); - __ inc(to, 1); - __ BIND(L_fill_2); - __ brx(Assembler::zero, false, Assembler::pt, L_fill_4); - __ delayed()->andcc(count, 4, G0); - __ stb(value, to, 0); - __ stb(value, to, 1); - __ inc(to, 2); - __ BIND(L_fill_4); - __ brx(Assembler::zero, false, Assembler::pt, L_exit); - __ delayed()->nop(); - __ stb(value, to, 0); - __ stb(value, to, 1); - __ stb(value, to, 2); - __ retl(); - __ delayed()->stb(value, to, 3); - } - - if (t == T_SHORT) { - Label L_fill_2; - __ BIND(L_fill_elements); - // in delay slot __ andcc(count, 1, G0); - __ brx(Assembler::zero, false, Assembler::pt, L_fill_2); - __ delayed()->andcc(count, 2, G0); - __ sth(value, to, 0); - __ inc(to, 2); - __ BIND(L_fill_2); - __ brx(Assembler::zero, false, Assembler::pt, L_exit); - __ delayed()->nop(); - __ sth(value, to, 0); - __ retl(); - __ delayed()->sth(value, to, 2); - } - return start; - } - - // - // Generate stub for conjoint short copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_conjoint_short_copy(bool aligned, address nooverlap_target, - address *entry, const char *name) { - // Do reverse copy. - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_skip_alignment, L_skip_alignment2, L_aligned_copy; - Label L_copy_2_bytes, L_copy_2_bytes_loop, L_exit; - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register end_from = from; // source array end address - const Register end_to = to; // destination array end address - - const Register byte_count = O3; // bytes count to copy - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - array_overlap_test(nooverlap_target, 1); - - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, !aligned, false); - - __ sllx(count, LogBytesPerShort, byte_count); - __ add(to, byte_count, end_to); // offset after last copied element - - // for short arrays, just do single element copy - __ cmp(count, 11); // 8 + 3 (22 bytes) - __ brx(Assembler::less, false, Assembler::pn, L_copy_2_bytes); - __ delayed()->add(from, byte_count, end_from); - - { - // Align end of arrays since they could be not aligned even - // when arrays itself are aligned. - - // copy 1 element if necessary to align 'end_to' on an 4 bytes - __ andcc(end_to, 3, G0); - __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); - __ delayed()->lduh(end_from, -2, O3); - __ dec(end_from, 2); - __ dec(end_to, 2); - __ dec(count); - __ sth(O3, end_to, 0); - __ BIND(L_skip_alignment); - - // copy 2 elements to align 'end_to' on an 8 byte boundary - __ andcc(end_to, 7, G0); - __ br(Assembler::zero, false, Assembler::pn, L_skip_alignment2); - __ delayed()->lduh(end_from, -2, O3); - __ dec(count, 2); - __ lduh(end_from, -4, O4); - __ dec(end_from, 4); - __ dec(end_to, 4); - __ sth(O3, end_to, 2); - __ sth(O4, end_to, 0); - __ BIND(L_skip_alignment2); - } - if (aligned) { - // Both arrays are aligned to 8-bytes in 64-bits VM. - // The 'count' is decremented in copy_16_bytes_backward_with_shift() - // in unaligned case. - __ dec(count, 8); - } else { - // Copy with shift 16 bytes per iteration if arrays do not have - // the same alignment mod 8, otherwise jump to the next - // code for aligned copy (and substracting 8 from 'count' before jump). - // The compare above (count >= 11) guarantes 'count' >= 16 bytes. - // Also jump over aligned copy after the copy with shift completed. - - copy_16_bytes_backward_with_shift(end_from, end_to, count, 8, - L_aligned_copy, L_copy_2_bytes); - } - // copy 4 elements (16 bytes) at a time - __ align(OptoLoopAlignment); - __ BIND(L_aligned_copy); - __ dec(end_from, 16); - __ ldx(end_from, 8, O3); - __ ldx(end_from, 0, O4); - __ dec(end_to, 16); - __ deccc(count, 8); - __ stx(O3, end_to, 8); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy); - __ delayed()->stx(O4, end_to, 0); - __ inc(count, 8); - - // copy 1 element (2 bytes) at a time - __ BIND(L_copy_2_bytes); - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit); - __ BIND(L_copy_2_bytes_loop); - __ dec(end_from, 2); - __ dec(end_to, 2); - __ lduh(end_from, 0, O4); - __ deccc(count); - __ brx(Assembler::greater, false, Assembler::pt, L_copy_2_bytes_loop); - __ delayed()->sth(O4, end_to, 0); - } - __ BIND(L_exit); - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jshort_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Helper methods for generate_disjoint_int_copy_core() - // - void copy_16_bytes_loop(Register from, Register to, Register count, int count_dec, - Label& L_loop, bool use_prefetch, bool use_bis) { - - __ align(OptoLoopAlignment); - __ BIND(L_loop); - if (use_prefetch) { - if (ArraycopySrcPrefetchDistance > 0) { - __ prefetch(from, ArraycopySrcPrefetchDistance, Assembler::severalReads); - } - if (ArraycopyDstPrefetchDistance > 0) { - __ prefetch(to, ArraycopyDstPrefetchDistance, Assembler::severalWritesAndPossiblyReads); - } - } - __ ldx(from, 4, O4); - __ ldx(from, 12, G4); - __ inc(to, 16); - __ inc(from, 16); - __ deccc(count, 4); // Can we do next iteration after this one? - - __ srlx(O4, 32, G3); - __ bset(G3, O3); - __ sllx(O4, 32, O4); - __ srlx(G4, 32, G3); - __ bset(G3, O4); - if (use_bis) { - __ stxa(O3, to, -16); - __ stxa(O4, to, -8); - } else { - __ stx(O3, to, -16); - __ stx(O4, to, -8); - } - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); - __ delayed()->sllx(G4, 32, O3); - - } - - // - // Generate core code for disjoint int copy (and oop copy on 32-bit). - // If "aligned" is true, the "from" and "to" addresses are assumed - // to be heapword aligned. - // - // Arguments: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - void generate_disjoint_int_copy_core(bool aligned) { - - Label L_skip_alignment, L_aligned_copy; - Label L_copy_4_bytes, L_copy_4_bytes_loop, L_exit; - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register offset = O5; // offset from start of arrays - // O3, O4, G3, G4 are used as temp registers - - // 'aligned' == true when it is known statically during compilation - // of this arraycopy call site that both 'from' and 'to' addresses - // are HeapWordSize aligned (see LibraryCallKit::basictype2arraycopy()). - // - // Aligned arrays have 4 bytes alignment in 32-bits VM - // and 8 bytes - in 64-bits VM. - // - if (!aligned) { - // The next check could be put under 'ifndef' since the code in - // generate_disjoint_long_copy_core() has own checks and set 'offset'. - - // for short arrays, just do single element copy - __ cmp(count, 5); // 4 + 1 (20 bytes) - __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_4_bytes); - __ delayed()->mov(G0, offset); - - // copy 1 element to align 'to' on an 8 byte boundary - __ andcc(to, 7, G0); - __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); - __ delayed()->ld(from, 0, O3); - __ inc(from, 4); - __ inc(to, 4); - __ dec(count); - __ st(O3, to, -4); - __ BIND(L_skip_alignment); - - // if arrays have same alignment mod 8, do 4 elements copy - __ andcc(from, 7, G0); - __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); - __ delayed()->ld(from, 0, O3); - - // - // Load 2 aligned 8-bytes chunks and use one from previous iteration - // to form 2 aligned 8-bytes chunks to store. - // - // copy_16_bytes_forward_with_shift() is not used here since this - // code is more optimal. - - // copy with shift 4 elements (16 bytes) at a time - __ dec(count, 4); // The cmp at the beginning guaranty count >= 4 - __ sllx(O3, 32, O3); - - disjoint_copy_core(from, to, count, 2, 16, &StubGenerator::copy_16_bytes_loop); - - __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes); - __ delayed()->inc(count, 4); // restore 'count' - - __ BIND(L_aligned_copy); - } // !aligned - - // copy 4 elements (16 bytes) at a time - __ and3(count, 1, G4); // Save - __ srl(count, 1, count); - generate_disjoint_long_copy_core(aligned); - __ mov(G4, count); // Restore - - // copy 1 element at a time - __ BIND(L_copy_4_bytes); - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit); - __ BIND(L_copy_4_bytes_loop); - __ ld(from, offset, O3); - __ deccc(count); - __ st(O3, to, offset); - __ brx(Assembler::notZero, false, Assembler::pt, L_copy_4_bytes_loop); - __ delayed()->inc(offset, 4); - __ BIND(L_exit); - } - - // - // Generate stub for disjoint int copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_disjoint_int_copy(bool aligned, address *entry, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - const Register count = O2; - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, !aligned, false); - generate_disjoint_int_copy_core(aligned); - } - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jint_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Generate core code for conjoint int copy (and oop copy on 32-bit). - // If "aligned" is true, the "from" and "to" addresses are assumed - // to be heapword aligned. - // - // Arguments: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - void generate_conjoint_int_copy_core(bool aligned) { - // Do reverse copy. - - Label L_skip_alignment, L_aligned_copy; - Label L_copy_16_bytes, L_copy_4_bytes, L_copy_4_bytes_loop, L_exit; - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register end_from = from; // source array end address - const Register end_to = to; // destination array end address - // O3, O4, O5, G3 are used as temp registers - - const Register byte_count = O3; // bytes count to copy - - __ sllx(count, LogBytesPerInt, byte_count); - __ add(to, byte_count, end_to); // offset after last copied element - - __ cmp(count, 5); // for short arrays, just do single element copy - __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_4_bytes); - __ delayed()->add(from, byte_count, end_from); - - // copy 1 element to align 'to' on an 8 byte boundary - __ andcc(end_to, 7, G0); - __ br(Assembler::zero, false, Assembler::pt, L_skip_alignment); - __ delayed()->nop(); - __ dec(count); - __ dec(end_from, 4); - __ dec(end_to, 4); - __ ld(end_from, 0, O4); - __ st(O4, end_to, 0); - __ BIND(L_skip_alignment); - - // Check if 'end_from' and 'end_to' has the same alignment. - __ andcc(end_from, 7, G0); - __ br(Assembler::zero, false, Assembler::pt, L_aligned_copy); - __ delayed()->dec(count, 4); // The cmp at the start guaranty cnt >= 4 - - // copy with shift 4 elements (16 bytes) at a time - // - // Load 2 aligned 8-bytes chunks and use one from previous iteration - // to form 2 aligned 8-bytes chunks to store. - // - __ ldx(end_from, -4, O3); - __ align(OptoLoopAlignment); - __ BIND(L_copy_16_bytes); - __ ldx(end_from, -12, O4); - __ deccc(count, 4); - __ ldx(end_from, -20, O5); - __ dec(end_to, 16); - __ dec(end_from, 16); - __ srlx(O3, 32, O3); - __ sllx(O4, 32, G3); - __ bset(G3, O3); - __ stx(O3, end_to, 8); - __ srlx(O4, 32, O4); - __ sllx(O5, 32, G3); - __ bset(O4, G3); - __ stx(G3, end_to, 0); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes); - __ delayed()->mov(O5, O3); - - __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes); - __ delayed()->inc(count, 4); - - // copy 4 elements (16 bytes) at a time - __ align(OptoLoopAlignment); - __ BIND(L_aligned_copy); - __ dec(end_from, 16); - __ ldx(end_from, 8, O3); - __ ldx(end_from, 0, O4); - __ dec(end_to, 16); - __ deccc(count, 4); - __ stx(O3, end_to, 8); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_aligned_copy); - __ delayed()->stx(O4, end_to, 0); - __ inc(count, 4); - - // copy 1 element (4 bytes) at a time - __ BIND(L_copy_4_bytes); - __ cmp_and_br_short(count, 0, Assembler::equal, Assembler::pt, L_exit); - __ BIND(L_copy_4_bytes_loop); - __ dec(end_from, 4); - __ dec(end_to, 4); - __ ld(end_from, 0, O4); - __ deccc(count); - __ brx(Assembler::greater, false, Assembler::pt, L_copy_4_bytes_loop); - __ delayed()->st(O4, end_to, 0); - __ BIND(L_exit); - } - - // - // Generate stub for conjoint int copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_conjoint_int_copy(bool aligned, address nooverlap_target, - address *entry, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - assert_clean_int(O2, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - array_overlap_test(nooverlap_target, 2); - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, !aligned, false); - generate_conjoint_int_copy_core(aligned); - } - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jint_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Helper methods for generate_disjoint_long_copy_core() - // - void copy_64_bytes_loop(Register from, Register to, Register count, int count_dec, - Label& L_loop, bool use_prefetch, bool use_bis) { - __ align(OptoLoopAlignment); - __ BIND(L_loop); - for (int off = 0; off < 64; off += 16) { - if (use_prefetch && (off & 31) == 0) { - if (ArraycopySrcPrefetchDistance > 0) { - __ prefetch(from, ArraycopySrcPrefetchDistance+off, Assembler::severalReads); - } - if (ArraycopyDstPrefetchDistance > 0) { - __ prefetch(to, ArraycopyDstPrefetchDistance+off, Assembler::severalWritesAndPossiblyReads); - } - } - __ ldx(from, off+0, O4); - __ ldx(from, off+8, O5); - if (use_bis) { - __ stxa(O4, to, off+0); - __ stxa(O5, to, off+8); - } else { - __ stx(O4, to, off+0); - __ stx(O5, to, off+8); - } - } - __ deccc(count, 8); - __ inc(from, 64); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_loop); - __ delayed()->inc(to, 64); - } - - // - // Generate core code for disjoint long copy (and oop copy on 64-bit). - // "aligned" is ignored, because we must make the stronger - // assumption that both addresses are always 64-bit aligned. - // - // Arguments: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - // count -= 2; - // if ( count >= 0 ) { // >= 2 elements - // if ( count > 6) { // >= 8 elements - // count -= 6; // original count - 8 - // do { - // copy_8_elements; - // count -= 8; - // } while ( count >= 0 ); - // count += 6; - // } - // if ( count >= 0 ) { // >= 2 elements - // do { - // copy_2_elements; - // } while ( (count=count-2) >= 0 ); - // } - // } - // count += 2; - // if ( count != 0 ) { // 1 element left - // copy_1_element; - // } - // - void generate_disjoint_long_copy_core(bool aligned) { - Label L_copy_8_bytes, L_copy_16_bytes, L_exit; - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register offset0 = O4; // element offset - const Register offset8 = O5; // next element offset - - __ deccc(count, 2); - __ mov(G0, offset0); // offset from start of arrays (0) - __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes ); - __ delayed()->add(offset0, 8, offset8); - - // Copy by 64 bytes chunks - - const Register from64 = O3; // source address - const Register to64 = G3; // destination address - __ subcc(count, 6, O3); - __ brx(Assembler::negative, false, Assembler::pt, L_copy_16_bytes ); - __ delayed()->mov(to, to64); - // Now we can use O4(offset0), O5(offset8) as temps - __ mov(O3, count); - // count >= 0 (original count - 8) - __ mov(from, from64); - - disjoint_copy_core(from64, to64, count, 3, 64, &StubGenerator::copy_64_bytes_loop); - - // Restore O4(offset0), O5(offset8) - __ sub(from64, from, offset0); - __ inccc(count, 6); // restore count - __ brx(Assembler::negative, false, Assembler::pn, L_copy_8_bytes ); - __ delayed()->add(offset0, 8, offset8); - - // Copy by 16 bytes chunks - __ align(OptoLoopAlignment); - __ BIND(L_copy_16_bytes); - __ ldx(from, offset0, O3); - __ ldx(from, offset8, G3); - __ deccc(count, 2); - __ stx(O3, to, offset0); - __ inc(offset0, 16); - __ stx(G3, to, offset8); - __ brx(Assembler::greaterEqual, false, Assembler::pt, L_copy_16_bytes); - __ delayed()->inc(offset8, 16); - - // Copy last 8 bytes - __ BIND(L_copy_8_bytes); - __ inccc(count, 2); - __ brx(Assembler::zero, true, Assembler::pn, L_exit ); - __ delayed()->mov(offset0, offset8); // Set O5 used by other stubs - __ ldx(from, offset0, O3); - __ stx(O3, to, offset0); - __ BIND(L_exit); - } - - // - // Generate stub for disjoint long copy. - // "aligned" is ignored, because we must make the stronger - // assumption that both addresses are always 64-bit aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_disjoint_long_copy(bool aligned, address *entry, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - assert_clean_int(O2, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, true, false); - generate_disjoint_long_copy_core(aligned); - } - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jlong_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // - // Generate core code for conjoint long copy (and oop copy on 64-bit). - // "aligned" is ignored, because we must make the stronger - // assumption that both addresses are always 64-bit aligned. - // - // Arguments: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - void generate_conjoint_long_copy_core(bool aligned) { - // Do reverse copy. - Label L_copy_8_bytes, L_copy_16_bytes, L_exit; - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - const Register offset8 = O4; // element offset - const Register offset0 = O5; // previous element offset - - __ subcc(count, 1, count); - __ brx(Assembler::lessEqual, false, Assembler::pn, L_copy_8_bytes ); - __ delayed()->sllx(count, LogBytesPerLong, offset8); - __ sub(offset8, 8, offset0); - __ align(OptoLoopAlignment); - __ BIND(L_copy_16_bytes); - __ ldx(from, offset8, O2); - __ ldx(from, offset0, O3); - __ stx(O2, to, offset8); - __ deccc(offset8, 16); // use offset8 as counter - __ stx(O3, to, offset0); - __ brx(Assembler::greater, false, Assembler::pt, L_copy_16_bytes); - __ delayed()->dec(offset0, 16); - - __ BIND(L_copy_8_bytes); - __ brx(Assembler::negative, false, Assembler::pn, L_exit ); - __ delayed()->nop(); - __ ldx(from, 0, O3); - __ stx(O3, to, 0); - __ BIND(L_exit); - } - - // Generate stub for conjoint long copy. - // "aligned" is ignored, because we must make the stronger - // assumption that both addresses are always 64-bit aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_conjoint_long_copy(bool aligned, address nooverlap_target, - address *entry, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - assert(aligned, "Should always be aligned"); - - assert_clean_int(O2, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) - BLOCK_COMMENT("Entry:"); - } - - array_overlap_test(nooverlap_target, 3); - { - // UnsafeCopyMemory page error: continue at UnsafeCopyMemory common_error_exit - UnsafeCopyMemoryMark ucmm(this, true, false); - generate_conjoint_long_copy_core(aligned); - } - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_jlong_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // Generate stub for disjoint oop copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_disjoint_oop_copy(bool aligned, address *entry, const char *name, - bool dest_uninitialized = false) { - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here - BLOCK_COMMENT("Entry:"); - } - - DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; - if (dest_uninitialized) { - decorators |= IS_DEST_UNINITIALIZED; - } - if (aligned) { - decorators |= ARRAYCOPY_ALIGNED; - } - - BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->arraycopy_prologue(_masm, decorators, T_OBJECT, from, to, count); - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - if (UseCompressedOops) { - generate_disjoint_int_copy_core(aligned); - } else { - generate_disjoint_long_copy_core(aligned); - } - - bs->arraycopy_epilogue(_masm, decorators, T_OBJECT, from, to, count); - - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_oop_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - // Generate stub for conjoint oop copy. If "aligned" is true, the - // "from" and "to" addresses are assumed to be heapword aligned. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - address generate_conjoint_oop_copy(bool aligned, address nooverlap_target, - address *entry, const char *name, - bool dest_uninitialized = false) { - - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - assert_clean_int(count, O3); // Make sure 'count' is clean int. - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here - BLOCK_COMMENT("Entry:"); - } - - array_overlap_test(nooverlap_target, LogBytesPerHeapOop); - - DecoratorSet decorators = IN_HEAP | IS_ARRAY; - if (dest_uninitialized) { - decorators |= IS_DEST_UNINITIALIZED; - } - if (aligned) { - decorators |= ARRAYCOPY_ALIGNED; - } - - BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->arraycopy_prologue(_masm, decorators, T_OBJECT, from, to, count); - - if (UseCompressedOops) { - generate_conjoint_int_copy_core(aligned); - } else { - generate_conjoint_long_copy_core(aligned); - } - - bs->arraycopy_epilogue(_masm, decorators, T_OBJECT, from, to, count); - - // O3, O4 are used as temp registers - inc_counter_np(SharedRuntime::_oop_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->mov(G0, O0); // return 0 - return start; - } - - - // Helper for generating a dynamic type check. - // Smashes only the given temp registers. - void generate_type_check(Register sub_klass, - Register super_check_offset, - Register super_klass, - Register temp, - Label& L_success) { - assert_different_registers(sub_klass, super_check_offset, super_klass, temp); - - BLOCK_COMMENT("type_check:"); - - Label L_miss, L_pop_to_miss; - - assert_clean_int(super_check_offset, temp); - - __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, noreg, - &L_success, &L_miss, NULL, - super_check_offset); - - BLOCK_COMMENT("type_check_slow_path:"); - __ save_frame(0); - __ check_klass_subtype_slow_path(sub_klass->after_save(), - super_klass->after_save(), - L0, L1, L2, L4, - NULL, &L_pop_to_miss); - __ ba(L_success); - __ delayed()->restore(); - - __ bind(L_pop_to_miss); - __ restore(); - - // Fall through on failure! - __ BIND(L_miss); - } - - - // Generate stub for checked oop copy. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 treated as signed - // ckoff: O3 (super_check_offset) - // ckval: O4 (super_klass) - // ret: O0 zero for success; (-1^K) where K is partial transfer count - // - address generate_checkcast_copy(const char *name, address *entry, bool dest_uninitialized = false) { - - const Register O0_from = O0; // source array address - const Register O1_to = O1; // destination array address - const Register O2_count = O2; // elements count - const Register O3_ckoff = O3; // super_check_offset - const Register O4_ckval = O4; // super_klass - - const Register O5_offset = O5; // loop var, with stride wordSize - const Register G1_remain = G1; // loop var, with stride -1 - const Register G3_oop = G3; // actual oop copied - const Register G4_klass = G4; // oop._klass - const Register G5_super = G5; // oop._klass._primary_supers[ckval] - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - -#ifdef ASSERT - // We sometimes save a frame (see generate_type_check below). - // If this will cause trouble, let's fail now instead of later. - __ save_frame(0); - __ restore(); -#endif - - assert_clean_int(O2_count, G1); // Make sure 'count' is clean int. - -#ifdef ASSERT - // caller guarantees that the arrays really are different - // otherwise, we would have to make conjoint checks - { Label L; - __ mov(O3, G1); // spill: overlap test smashes O3 - __ mov(O4, G4); // spill: overlap test smashes O4 - array_overlap_test(L, LogBytesPerHeapOop); - __ stop("checkcast_copy within a single array"); - __ bind(L); - __ mov(G1, O3); - __ mov(G4, O4); - } -#endif //ASSERT - - if (entry != NULL) { - *entry = __ pc(); - // caller can pass a 64-bit byte count here (from generic stub) - BLOCK_COMMENT("Entry:"); - } - - DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST; - if (dest_uninitialized) { - decorators |= IS_DEST_UNINITIALIZED; - } - - BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); - bs->arraycopy_prologue(_masm, decorators, T_OBJECT, O0_from, O1_to, O2_count); - - Label load_element, store_element, do_epilogue, fail, done; - __ addcc(O2_count, 0, G1_remain); // initialize loop index, and test it - __ brx(Assembler::notZero, false, Assembler::pt, load_element); - __ delayed()->mov(G0, O5_offset); // offset from start of arrays - - // Empty array: Nothing to do. - inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->set(0, O0); // return 0 on (trivial) success - - // ======== begin loop ======== - // (Loop is rotated; its entry is load_element.) - // Loop variables: - // (O5 = 0; ; O5 += wordSize) --- offset from src, dest arrays - // (O2 = len; O2 != 0; O2--) --- number of oops *remaining* - // G3, G4, G5 --- current oop, oop.klass, oop.klass.super - __ align(OptoLoopAlignment); - - __ BIND(store_element); - __ deccc(G1_remain); // decrement the count - __ store_heap_oop(G3_oop, O1_to, O5_offset, noreg, AS_RAW); // store the oop - __ inc(O5_offset, heapOopSize); // step to next offset - __ brx(Assembler::zero, true, Assembler::pt, do_epilogue); - __ delayed()->set(0, O0); // return -1 on success - - // ======== loop entry is here ======== - __ BIND(load_element); - __ load_heap_oop(O0_from, O5_offset, G3_oop, noreg, AS_RAW); // load the oop - __ br_null_short(G3_oop, Assembler::pt, store_element); - - __ load_klass(G3_oop, G4_klass); // query the object klass - - generate_type_check(G4_klass, O3_ckoff, O4_ckval, G5_super, - // branch to this on success: - store_element); - // ======== end loop ======== - - // It was a real error; we must depend on the caller to finish the job. - // Register G1 has number of *remaining* oops, O2 number of *total* oops. - // Emit GC store barriers for the oops we have copied (O2 minus G1), - // and report their number to the caller. - __ BIND(fail); - __ subcc(O2_count, G1_remain, O2_count); - __ brx(Assembler::zero, false, Assembler::pt, done); - __ delayed()->not1(O2_count, O0); // report (-1^K) to caller - - __ BIND(do_epilogue); - bs->arraycopy_epilogue(_masm, decorators, T_OBJECT, O0_from, O1_to, O2_count); - - __ BIND(done); - inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, O3, O4); - __ retl(); - __ delayed()->nop(); // return value in 00 - - return start; - } - - - // Generate 'unsafe' array copy stub - // Though just as safe as the other stubs, it takes an unscaled - // size_t argument instead of an element count. - // - // Arguments for generated stub: - // from: O0 - // to: O1 - // count: O2 byte count, treated as ssize_t, can be zero - // - // Examines the alignment of the operands and dispatches - // to a long, int, short, or byte copy loop. - // - address generate_unsafe_copy(const char* name, - address byte_copy_entry, - address short_copy_entry, - address int_copy_entry, - address long_copy_entry) { - - const Register O0_from = O0; // source array address - const Register O1_to = O1; // destination array address - const Register O2_count = O2; // elements count - - const Register G1_bits = G1; // test copy of low bits - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - // bump this on entry, not on exit: - inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, G1, G3); - - __ or3(O0_from, O1_to, G1_bits); - __ or3(O2_count, G1_bits, G1_bits); - - __ btst(BytesPerLong-1, G1_bits); - __ br(Assembler::zero, true, Assembler::pt, - long_copy_entry, relocInfo::runtime_call_type); - // scale the count on the way out: - __ delayed()->srax(O2_count, LogBytesPerLong, O2_count); - - __ btst(BytesPerInt-1, G1_bits); - __ br(Assembler::zero, true, Assembler::pt, - int_copy_entry, relocInfo::runtime_call_type); - // scale the count on the way out: - __ delayed()->srax(O2_count, LogBytesPerInt, O2_count); - - __ btst(BytesPerShort-1, G1_bits); - __ br(Assembler::zero, true, Assembler::pt, - short_copy_entry, relocInfo::runtime_call_type); - // scale the count on the way out: - __ delayed()->srax(O2_count, LogBytesPerShort, O2_count); - - __ br(Assembler::always, false, Assembler::pt, - byte_copy_entry, relocInfo::runtime_call_type); - __ delayed()->nop(); - - return start; - } - - - // Perform range checks on the proposed arraycopy. - // Kills the two temps, but nothing else. - // Also, clean the sign bits of src_pos and dst_pos. - void arraycopy_range_checks(Register src, // source array oop (O0) - Register src_pos, // source position (O1) - Register dst, // destination array oo (O2) - Register dst_pos, // destination position (O3) - Register length, // length of copy (O4) - Register temp1, Register temp2, - Label& L_failed) { - BLOCK_COMMENT("arraycopy_range_checks:"); - - // if (src_pos + length > arrayOop(src)->length() ) FAIL; - - const Register array_length = temp1; // scratch - const Register end_pos = temp2; // scratch - - // Note: This next instruction may be in the delay slot of a branch: - __ add(length, src_pos, end_pos); // src_pos + length - __ lduw(src, arrayOopDesc::length_offset_in_bytes(), array_length); - __ cmp(end_pos, array_length); - __ br(Assembler::greater, false, Assembler::pn, L_failed); - - // if (dst_pos + length > arrayOop(dst)->length() ) FAIL; - __ delayed()->add(length, dst_pos, end_pos); // dst_pos + length - __ lduw(dst, arrayOopDesc::length_offset_in_bytes(), array_length); - __ cmp(end_pos, array_length); - __ br(Assembler::greater, false, Assembler::pn, L_failed); - - // Have to clean up high 32-bits of 'src_pos' and 'dst_pos'. - // Move with sign extension can be used since they are positive. - __ delayed()->signx(src_pos, src_pos); - __ signx(dst_pos, dst_pos); - - BLOCK_COMMENT("arraycopy_range_checks done"); - } - - - // - // Generate generic array copy stubs - // - // Input: - // O0 - src oop - // O1 - src_pos - // O2 - dst oop - // O3 - dst_pos - // O4 - element count - // - // Output: - // O0 == 0 - success - // O0 == -1 - need to call System.arraycopy - // - address generate_generic_copy(const char *name, - address entry_jbyte_arraycopy, - address entry_jshort_arraycopy, - address entry_jint_arraycopy, - address entry_oop_arraycopy, - address entry_jlong_arraycopy, - address entry_checkcast_arraycopy) { - Label L_failed, L_objArray; - - // Input registers - const Register src = O0; // source array oop - const Register src_pos = O1; // source position - const Register dst = O2; // destination array oop - const Register dst_pos = O3; // destination position - const Register length = O4; // elements count - - // registers used as temp - const Register G3_src_klass = G3; // source array klass - const Register G4_dst_klass = G4; // destination array klass - const Register G5_lh = G5; // layout handler - const Register O5_temp = O5; - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - // bump this on entry, not on exit: - inc_counter_np(SharedRuntime::_generic_array_copy_ctr, G1, G3); - - // In principle, the int arguments could be dirty. - //assert_clean_int(src_pos, G1); - //assert_clean_int(dst_pos, G1); - //assert_clean_int(length, G1); - - //----------------------------------------------------------------------- - // Assembler stubs will be used for this call to arraycopy - // if the following conditions are met: - // - // (1) src and dst must not be null. - // (2) src_pos must not be negative. - // (3) dst_pos must not be negative. - // (4) length must not be negative. - // (5) src klass and dst klass should be the same and not NULL. - // (6) src and dst should be arrays. - // (7) src_pos + length must not exceed length of src. - // (8) dst_pos + length must not exceed length of dst. - BLOCK_COMMENT("arraycopy initial argument checks"); - - // if (src == NULL) return -1; - __ br_null(src, false, Assembler::pn, L_failed); - - // if (src_pos < 0) return -1; - __ delayed()->tst(src_pos); - __ br(Assembler::negative, false, Assembler::pn, L_failed); - __ delayed()->nop(); - - // if (dst == NULL) return -1; - __ br_null(dst, false, Assembler::pn, L_failed); - - // if (dst_pos < 0) return -1; - __ delayed()->tst(dst_pos); - __ br(Assembler::negative, false, Assembler::pn, L_failed); - - // if (length < 0) return -1; - __ delayed()->tst(length); - __ br(Assembler::negative, false, Assembler::pn, L_failed); - - BLOCK_COMMENT("arraycopy argument klass checks"); - // get src->klass() - if (UseCompressedClassPointers) { - __ delayed()->nop(); // ??? not good - __ load_klass(src, G3_src_klass); - } else { - __ delayed()->ld_ptr(src, oopDesc::klass_offset_in_bytes(), G3_src_klass); - } - -#ifdef ASSERT - // assert(src->klass() != NULL); - BLOCK_COMMENT("assert klasses not null"); - { Label L_a, L_b; - __ br_notnull_short(G3_src_klass, Assembler::pt, L_b); // it is broken if klass is NULL - __ bind(L_a); - __ stop("broken null klass"); - __ bind(L_b); - __ load_klass(dst, G4_dst_klass); - __ br_null(G4_dst_klass, false, Assembler::pn, L_a); // this would be broken also - __ delayed()->mov(G0, G4_dst_klass); // scribble the temp - BLOCK_COMMENT("assert done"); - } -#endif - - // Load layout helper - // - // |array_tag| | header_size | element_type | |log2_element_size| - // 32 30 24 16 8 2 0 - // - // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 - // - - int lh_offset = in_bytes(Klass::layout_helper_offset()); - - // Load 32-bits signed value. Use br() instruction with it to check icc. - __ lduw(G3_src_klass, lh_offset, G5_lh); - - if (UseCompressedClassPointers) { - __ load_klass(dst, G4_dst_klass); - } - // Handle objArrays completely differently... - juint objArray_lh = Klass::array_layout_helper(T_OBJECT); - __ set(objArray_lh, O5_temp); - __ cmp(G5_lh, O5_temp); - __ br(Assembler::equal, false, Assembler::pt, L_objArray); - if (UseCompressedClassPointers) { - __ delayed()->nop(); - } else { - __ delayed()->ld_ptr(dst, oopDesc::klass_offset_in_bytes(), G4_dst_klass); - } - - // if (src->klass() != dst->klass()) return -1; - __ cmp_and_brx_short(G3_src_klass, G4_dst_klass, Assembler::notEqual, Assembler::pn, L_failed); - - // if (!src->is_Array()) return -1; - __ cmp(G5_lh, Klass::_lh_neutral_value); // < 0 - __ br(Assembler::greaterEqual, false, Assembler::pn, L_failed); - - // At this point, it is known to be a typeArray (array_tag 0x3). -#ifdef ASSERT - __ delayed()->nop(); - { Label L; - jint lh_prim_tag_in_place = (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); - __ set(lh_prim_tag_in_place, O5_temp); - __ cmp(G5_lh, O5_temp); - __ br(Assembler::greaterEqual, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("must be a primitive array"); - __ bind(L); - } -#else - __ delayed(); // match next insn to prev branch -#endif - - arraycopy_range_checks(src, src_pos, dst, dst_pos, length, - O5_temp, G4_dst_klass, L_failed); - - // TypeArrayKlass - // - // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); - // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); - // - - const Register G4_offset = G4_dst_klass; // array offset - const Register G3_elsize = G3_src_klass; // log2 element size - - __ srl(G5_lh, Klass::_lh_header_size_shift, G4_offset); - __ and3(G4_offset, Klass::_lh_header_size_mask, G4_offset); // array_offset - __ add(src, G4_offset, src); // src array offset - __ add(dst, G4_offset, dst); // dst array offset - __ and3(G5_lh, Klass::_lh_log2_element_size_mask, G3_elsize); // log2 element size - - // next registers should be set before the jump to corresponding stub - const Register from = O0; // source array address - const Register to = O1; // destination array address - const Register count = O2; // elements count - - // 'from', 'to', 'count' registers should be set in this order - // since they are the same as 'src', 'src_pos', 'dst'. - - BLOCK_COMMENT("scale indexes to element size"); - __ sll_ptr(src_pos, G3_elsize, src_pos); - __ sll_ptr(dst_pos, G3_elsize, dst_pos); - __ add(src, src_pos, from); // src_addr - __ add(dst, dst_pos, to); // dst_addr - - BLOCK_COMMENT("choose copy loop based on element size"); - __ cmp(G3_elsize, 0); - __ br(Assembler::equal, true, Assembler::pt, entry_jbyte_arraycopy); - __ delayed()->signx(length, count); // length - - __ cmp(G3_elsize, LogBytesPerShort); - __ br(Assembler::equal, true, Assembler::pt, entry_jshort_arraycopy); - __ delayed()->signx(length, count); // length - - __ cmp(G3_elsize, LogBytesPerInt); - __ br(Assembler::equal, true, Assembler::pt, entry_jint_arraycopy); - __ delayed()->signx(length, count); // length -#ifdef ASSERT - { Label L; - __ cmp_and_br_short(G3_elsize, LogBytesPerLong, Assembler::equal, Assembler::pt, L); - __ stop("must be long copy, but elsize is wrong"); - __ bind(L); - } -#endif - __ br(Assembler::always, false, Assembler::pt, entry_jlong_arraycopy); - __ delayed()->signx(length, count); // length - - // ObjArrayKlass - __ BIND(L_objArray); - // live at this point: G3_src_klass, G4_dst_klass, src[_pos], dst[_pos], length - - Label L_plain_copy, L_checkcast_copy; - // test array classes for subtyping - __ cmp(G3_src_klass, G4_dst_klass); // usual case is exact equality - __ brx(Assembler::notEqual, true, Assembler::pn, L_checkcast_copy); - __ delayed()->lduw(G4_dst_klass, lh_offset, O5_temp); // hoisted from below - - // Identically typed arrays can be copied without element-wise checks. - arraycopy_range_checks(src, src_pos, dst, dst_pos, length, - O5_temp, G5_lh, L_failed); - - __ add(src, arrayOopDesc::base_offset_in_bytes(T_OBJECT), src); //src offset - __ add(dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT), dst); //dst offset - __ sll_ptr(src_pos, LogBytesPerHeapOop, src_pos); - __ sll_ptr(dst_pos, LogBytesPerHeapOop, dst_pos); - __ add(src, src_pos, from); // src_addr - __ add(dst, dst_pos, to); // dst_addr - __ BIND(L_plain_copy); - __ br(Assembler::always, false, Assembler::pt, entry_oop_arraycopy); - __ delayed()->signx(length, count); // length - - __ BIND(L_checkcast_copy); - // live at this point: G3_src_klass, G4_dst_klass - { - // Before looking at dst.length, make sure dst is also an objArray. - // lduw(G4_dst_klass, lh_offset, O5_temp); // hoisted to delay slot - __ cmp(G5_lh, O5_temp); - __ br(Assembler::notEqual, false, Assembler::pn, L_failed); - - // It is safe to examine both src.length and dst.length. - __ delayed(); // match next insn to prev branch - arraycopy_range_checks(src, src_pos, dst, dst_pos, length, - O5_temp, G5_lh, L_failed); - - // Marshal the base address arguments now, freeing registers. - __ add(src, arrayOopDesc::base_offset_in_bytes(T_OBJECT), src); //src offset - __ add(dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT), dst); //dst offset - __ sll_ptr(src_pos, LogBytesPerHeapOop, src_pos); - __ sll_ptr(dst_pos, LogBytesPerHeapOop, dst_pos); - __ add(src, src_pos, from); // src_addr - __ add(dst, dst_pos, to); // dst_addr - __ signx(length, count); // length (reloaded) - - Register sco_temp = O3; // this register is free now - assert_different_registers(from, to, count, sco_temp, - G4_dst_klass, G3_src_klass); - - // Generate the type check. - int sco_offset = in_bytes(Klass::super_check_offset_offset()); - __ lduw(G4_dst_klass, sco_offset, sco_temp); - generate_type_check(G3_src_klass, sco_temp, G4_dst_klass, - O5_temp, L_plain_copy); - - // Fetch destination element klass from the ObjArrayKlass header. - int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); - - // the checkcast_copy loop needs two extra arguments: - __ ld_ptr(G4_dst_klass, ek_offset, O4); // dest elem klass - // lduw(O4, sco_offset, O3); // sco of elem klass - - __ br(Assembler::always, false, Assembler::pt, entry_checkcast_arraycopy); - __ delayed()->lduw(O4, sco_offset, O3); - } - - __ BIND(L_failed); - __ retl(); - __ delayed()->sub(G0, 1, O0); // return -1 - return start; - } - - // - // Generate stub for heap zeroing. - // "to" address is aligned to jlong (8 bytes). - // - // Arguments for generated stub: - // to: O0 - // count: O1 treated as signed (count of HeapWord) - // count could be 0 - // - address generate_zero_aligned_words(const char* name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - const Register to = O0; // source array address - const Register count = O1; // HeapWords count - const Register temp = O2; // scratch - - Label Ldone; - __ sllx(count, LogHeapWordSize, count); // to bytes count - // Use BIS for zeroing - __ bis_zeroing(to, count, temp, Ldone); - __ bind(Ldone); - __ retl(); - __ delayed()->nop(); - return start; -} - - void generate_arraycopy_stubs() { - address entry; - address entry_jbyte_arraycopy; - address entry_jshort_arraycopy; - address entry_jint_arraycopy; - address entry_oop_arraycopy; - address entry_jlong_arraycopy; - address entry_checkcast_arraycopy; - - address ucm_common_error_exit = generate_unsafecopy_common_error_exit(); - UnsafeCopyMemory::set_common_exit_stub_pc(ucm_common_error_exit); - - //*** jbyte - // Always need aligned and unaligned versions - StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(false, &entry, - "jbyte_disjoint_arraycopy"); - StubRoutines::_jbyte_arraycopy = generate_conjoint_byte_copy(false, entry, - &entry_jbyte_arraycopy, - "jbyte_arraycopy"); - StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(true, &entry, - "arrayof_jbyte_disjoint_arraycopy"); - StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_byte_copy(true, entry, NULL, - "arrayof_jbyte_arraycopy"); - - //*** jshort - // Always need aligned and unaligned versions - StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_short_copy(false, &entry, - "jshort_disjoint_arraycopy"); - StubRoutines::_jshort_arraycopy = generate_conjoint_short_copy(false, entry, - &entry_jshort_arraycopy, - "jshort_arraycopy"); - StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_short_copy(true, &entry, - "arrayof_jshort_disjoint_arraycopy"); - StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_short_copy(true, entry, NULL, - "arrayof_jshort_arraycopy"); - - //*** jint - // Aligned versions - StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_int_copy(true, &entry, - "arrayof_jint_disjoint_arraycopy"); - StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_int_copy(true, entry, &entry_jint_arraycopy, - "arrayof_jint_arraycopy"); - // In 64 bit we need both aligned and unaligned versions of jint arraycopy. - // entry_jint_arraycopy always points to the unaligned version (notice that we overwrite it). - StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_int_copy(false, &entry, - "jint_disjoint_arraycopy"); - StubRoutines::_jint_arraycopy = generate_conjoint_int_copy(false, entry, - &entry_jint_arraycopy, - "jint_arraycopy"); - - //*** jlong - // It is always aligned - StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_long_copy(true, &entry, - "arrayof_jlong_disjoint_arraycopy"); - StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_long_copy(true, entry, &entry_jlong_arraycopy, - "arrayof_jlong_arraycopy"); - StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy; - StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy; - - - //*** oops - // Aligned versions - StubRoutines::_arrayof_oop_disjoint_arraycopy = generate_disjoint_oop_copy(true, &entry, - "arrayof_oop_disjoint_arraycopy"); - StubRoutines::_arrayof_oop_arraycopy = generate_conjoint_oop_copy(true, entry, &entry_oop_arraycopy, - "arrayof_oop_arraycopy"); - // Aligned versions without pre-barriers - StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(true, &entry, - "arrayof_oop_disjoint_arraycopy_uninit", - /*dest_uninitialized*/true); - StubRoutines::_arrayof_oop_arraycopy_uninit = generate_conjoint_oop_copy(true, entry, NULL, - "arrayof_oop_arraycopy_uninit", - /*dest_uninitialized*/true); - if (UseCompressedOops) { - // With compressed oops we need unaligned versions, notice that we overwrite entry_oop_arraycopy. - StubRoutines::_oop_disjoint_arraycopy = generate_disjoint_oop_copy(false, &entry, - "oop_disjoint_arraycopy"); - StubRoutines::_oop_arraycopy = generate_conjoint_oop_copy(false, entry, &entry_oop_arraycopy, - "oop_arraycopy"); - // Unaligned versions without pre-barriers - StubRoutines::_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(false, &entry, - "oop_disjoint_arraycopy_uninit", - /*dest_uninitialized*/true); - StubRoutines::_oop_arraycopy_uninit = generate_conjoint_oop_copy(false, entry, NULL, - "oop_arraycopy_uninit", - /*dest_uninitialized*/true); - } else { - // oop arraycopy is always aligned on 32bit and 64bit without compressed oops - StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy; - StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy; - StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit; - StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit; - } - - StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", &entry_checkcast_arraycopy); - StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", NULL, - /*dest_uninitialized*/true); - - StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", - entry_jbyte_arraycopy, - entry_jshort_arraycopy, - entry_jint_arraycopy, - entry_jlong_arraycopy); - StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", - entry_jbyte_arraycopy, - entry_jshort_arraycopy, - entry_jint_arraycopy, - entry_oop_arraycopy, - entry_jlong_arraycopy, - entry_checkcast_arraycopy); - - StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); - StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); - StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); - StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); - StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); - StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); - - if (UseBlockZeroing) { - StubRoutines::_zero_aligned_words = generate_zero_aligned_words("zero_aligned_words"); - } - } - - address generate_aescrypt_encryptBlock() { - // required since we read expanded key 'int' array starting first element without alignment considerations - assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0, - "the following code assumes that first element of an int array is aligned to 8 bytes"); - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock"); - Label L_load_misaligned_input, L_load_expanded_key, L_doLast128bit, L_storeOutput, L_store_misaligned_output; - address start = __ pc(); - Register from = O0; // source byte array - Register to = O1; // destination byte array - Register key = O2; // expanded key array - const Register keylen = O4; //reg for storing expanded key array length - - // read expanded key length - __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0); - - // Method to address arbitrary alignment for load instructions: - // Check last 3 bits of 'from' address to see if it is aligned to 8-byte boundary - // If zero/aligned then continue with double FP load instructions - // If not zero/mis-aligned then alignaddr will set GSR.align with number of bytes to skip during faligndata - // alignaddr will also convert arbitrary aligned 'from' address to nearest 8-byte aligned address - // load 3 * 8-byte components (to read 16 bytes input) in 3 different FP regs starting at this aligned address - // faligndata will then extract (based on GSR.align value) the appropriate 8 bytes from the 2 source regs - - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input); - __ delayed()->alignaddr(from, G0, from); - - // aligned case: load input into F54-F56 - __ ldf(FloatRegisterImpl::D, from, 0, F54); - __ ldf(FloatRegisterImpl::D, from, 8, F56); - __ ba_short(L_load_expanded_key); - - __ BIND(L_load_misaligned_input); - __ ldf(FloatRegisterImpl::D, from, 0, F54); - __ ldf(FloatRegisterImpl::D, from, 8, F56); - __ ldf(FloatRegisterImpl::D, from, 16, F58); - __ faligndata(F54, F56, F54); - __ faligndata(F56, F58, F56); - - __ BIND(L_load_expanded_key); - // Since we load expanded key buffers starting first element, 8-byte alignment is guaranteed - for ( int i = 0; i <= 38; i += 2 ) { - __ ldf(FloatRegisterImpl::D, key, i*4, as_FloatRegister(i)); - } - - // perform cipher transformation - __ fxor(FloatRegisterImpl::D, F0, F54, F54); - __ fxor(FloatRegisterImpl::D, F2, F56, F56); - // rounds 1 through 8 - for ( int i = 4; i <= 28; i += 8 ) { - __ aes_eround01(as_FloatRegister(i), F54, F56, F58); - __ aes_eround23(as_FloatRegister(i+2), F54, F56, F60); - __ aes_eround01(as_FloatRegister(i+4), F58, F60, F54); - __ aes_eround23(as_FloatRegister(i+6), F58, F60, F56); - } - __ aes_eround01(F36, F54, F56, F58); //round 9 - __ aes_eround23(F38, F54, F56, F60); - - // 128-bit original key size - __ cmp_and_brx_short(keylen, 44, Assembler::equal, Assembler::pt, L_doLast128bit); - - for ( int i = 40; i <= 50; i += 2 ) { - __ ldf(FloatRegisterImpl::D, key, i*4, as_FloatRegister(i) ); - } - __ aes_eround01(F40, F58, F60, F54); //round 10 - __ aes_eround23(F42, F58, F60, F56); - __ aes_eround01(F44, F54, F56, F58); //round 11 - __ aes_eround23(F46, F54, F56, F60); - - // 192-bit original key size - __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pt, L_storeOutput); - - __ ldf(FloatRegisterImpl::D, key, 208, F52); - __ aes_eround01(F48, F58, F60, F54); //round 12 - __ aes_eround23(F50, F58, F60, F56); - __ ldf(FloatRegisterImpl::D, key, 216, F46); - __ ldf(FloatRegisterImpl::D, key, 224, F48); - __ ldf(FloatRegisterImpl::D, key, 232, F50); - __ aes_eround01(F52, F54, F56, F58); //round 13 - __ aes_eround23(F46, F54, F56, F60); - __ ba_short(L_storeOutput); - - __ BIND(L_doLast128bit); - __ ldf(FloatRegisterImpl::D, key, 160, F48); - __ ldf(FloatRegisterImpl::D, key, 168, F50); - - __ BIND(L_storeOutput); - // perform last round of encryption common for all key sizes - __ aes_eround01_l(F48, F58, F60, F54); //last round - __ aes_eround23_l(F50, F58, F60, F56); - - // Method to address arbitrary alignment for store instructions: - // Check last 3 bits of 'dest' address to see if it is aligned to 8-byte boundary - // If zero/aligned then continue with double FP store instructions - // If not zero/mis-aligned then edge8n will generate edge mask in result reg (O3 in below case) - // Example: If dest address is 0x07 and nearest 8-byte aligned address is 0x00 then edge mask will be 00000001 - // Compute (8-n) where n is # of bytes skipped by partial store(stpartialf) inst from edge mask, n=7 in this case - // We get the value of n from the andcc that checks 'dest' alignment. n is available in O5 in below case. - // Set GSR.align to (8-n) using alignaddr - // Circular byte shift store values by n places so that the original bytes are at correct position for stpartialf - // Set the arbitrarily aligned 'dest' address to nearest 8-byte aligned address - // Store (partial) the original first (8-n) bytes starting at the original 'dest' address - // Negate the edge mask so that the subsequent stpartialf can store the original (8-n-1)th through 8th bytes at appropriate address - // We need to execute this process for both the 8-byte result values - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, O5); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output); - __ delayed()->edge8n(to, G0, O3); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F54, to, 0); - __ retl(); - __ delayed()->stf(FloatRegisterImpl::D, F56, to, 8); - - __ BIND(L_store_misaligned_output); - __ add(to, 8, O4); - __ mov(8, O2); - __ sub(O2, O5, O2); - __ alignaddr(O2, G0, O2); - __ faligndata(F54, F54, F54); - __ faligndata(F56, F56, F56); - __ and3(to, -8, to); - __ and3(O4, -8, O4); - __ stpartialf(to, O3, F54, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(O4, O3, F56, Assembler::ASI_PST8_PRIMARY); - __ add(to, 8, to); - __ add(O4, 8, O4); - __ orn(G0, O3, O3); - __ stpartialf(to, O3, F54, Assembler::ASI_PST8_PRIMARY); - __ retl(); - __ delayed()->stpartialf(O4, O3, F56, Assembler::ASI_PST8_PRIMARY); - - return start; - } - - address generate_aescrypt_decryptBlock() { - assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0, - "the following code assumes that first element of an int array is aligned to 8 bytes"); - // required since we read original key 'byte' array as well in the decryption stubs - assert((arrayOopDesc::base_offset_in_bytes(T_BYTE) & 7) == 0, - "the following code assumes that first element of a byte array is aligned to 8 bytes"); - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock"); - address start = __ pc(); - Label L_load_misaligned_input, L_load_original_key, L_expand192bit, L_expand256bit, L_reload_misaligned_input; - Label L_256bit_transform, L_common_transform, L_store_misaligned_output; - Register from = O0; // source byte array - Register to = O1; // destination byte array - Register key = O2; // expanded key array - Register original_key = O3; // original key array only required during decryption - const Register keylen = O4; // reg for storing expanded key array length - - // read expanded key array length - __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0); - - // save 'from' since we may need to recheck alignment in case of 256-bit decryption - __ mov(from, G1); - - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input); - __ delayed()->alignaddr(from, G0, from); - - // aligned case: load input into F52-F54 - __ ldf(FloatRegisterImpl::D, from, 0, F52); - __ ldf(FloatRegisterImpl::D, from, 8, F54); - __ ba_short(L_load_original_key); - - __ BIND(L_load_misaligned_input); - __ ldf(FloatRegisterImpl::D, from, 0, F52); - __ ldf(FloatRegisterImpl::D, from, 8, F54); - __ ldf(FloatRegisterImpl::D, from, 16, F56); - __ faligndata(F52, F54, F52); - __ faligndata(F54, F56, F54); - - __ BIND(L_load_original_key); - // load original key from SunJCE expanded decryption key - // Since we load original key buffer starting first element, 8-byte alignment is guaranteed - for ( int i = 0; i <= 3; i++ ) { - __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i)); - } - - // 256-bit original key size - __ cmp_and_brx_short(keylen, 60, Assembler::equal, Assembler::pn, L_expand256bit); - - // 192-bit original key size - __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_expand192bit); - - // 128-bit original key size - // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions - for ( int i = 0; i <= 36; i += 4 ) { - __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+2), i/4, as_FloatRegister(i+4)); - __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+4), as_FloatRegister(i+6)); - } - - // perform 128-bit key specific inverse cipher transformation - __ fxor(FloatRegisterImpl::D, F42, F54, F54); - __ fxor(FloatRegisterImpl::D, F40, F52, F52); - __ ba_short(L_common_transform); - - __ BIND(L_expand192bit); - - // start loading rest of the 192-bit key - __ ldf(FloatRegisterImpl::S, original_key, 16, F4); - __ ldf(FloatRegisterImpl::S, original_key, 20, F5); - - // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions - for ( int i = 0; i <= 36; i += 6 ) { - __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+4), i/6, as_FloatRegister(i+6)); - __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+6), as_FloatRegister(i+8)); - __ aes_kexpand2(as_FloatRegister(i+4), as_FloatRegister(i+8), as_FloatRegister(i+10)); - } - __ aes_kexpand1(F42, F46, 7, F48); - __ aes_kexpand2(F44, F48, F50); - - // perform 192-bit key specific inverse cipher transformation - __ fxor(FloatRegisterImpl::D, F50, F54, F54); - __ fxor(FloatRegisterImpl::D, F48, F52, F52); - __ aes_dround23(F46, F52, F54, F58); - __ aes_dround01(F44, F52, F54, F56); - __ aes_dround23(F42, F56, F58, F54); - __ aes_dround01(F40, F56, F58, F52); - __ ba_short(L_common_transform); - - __ BIND(L_expand256bit); - - // load rest of the 256-bit key - for ( int i = 4; i <= 7; i++ ) { - __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i)); - } - - // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions - for ( int i = 0; i <= 40; i += 8 ) { - __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+6), i/8, as_FloatRegister(i+8)); - __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+8), as_FloatRegister(i+10)); - __ aes_kexpand0(as_FloatRegister(i+4), as_FloatRegister(i+10), as_FloatRegister(i+12)); - __ aes_kexpand2(as_FloatRegister(i+6), as_FloatRegister(i+12), as_FloatRegister(i+14)); - } - __ aes_kexpand1(F48, F54, 6, F56); - __ aes_kexpand2(F50, F56, F58); - - for ( int i = 0; i <= 6; i += 2 ) { - __ fsrc2(FloatRegisterImpl::D, as_FloatRegister(58-i), as_FloatRegister(i)); - } - - // reload original 'from' address - __ mov(G1, from); - - // re-check 8-byte alignment - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_reload_misaligned_input); - __ delayed()->alignaddr(from, G0, from); - - // aligned case: load input into F52-F54 - __ ldf(FloatRegisterImpl::D, from, 0, F52); - __ ldf(FloatRegisterImpl::D, from, 8, F54); - __ ba_short(L_256bit_transform); - - __ BIND(L_reload_misaligned_input); - __ ldf(FloatRegisterImpl::D, from, 0, F52); - __ ldf(FloatRegisterImpl::D, from, 8, F54); - __ ldf(FloatRegisterImpl::D, from, 16, F56); - __ faligndata(F52, F54, F52); - __ faligndata(F54, F56, F54); - - // perform 256-bit key specific inverse cipher transformation - __ BIND(L_256bit_transform); - __ fxor(FloatRegisterImpl::D, F0, F54, F54); - __ fxor(FloatRegisterImpl::D, F2, F52, F52); - __ aes_dround23(F4, F52, F54, F58); - __ aes_dround01(F6, F52, F54, F56); - __ aes_dround23(F50, F56, F58, F54); - __ aes_dround01(F48, F56, F58, F52); - __ aes_dround23(F46, F52, F54, F58); - __ aes_dround01(F44, F52, F54, F56); - __ aes_dround23(F42, F56, F58, F54); - __ aes_dround01(F40, F56, F58, F52); - - for ( int i = 0; i <= 7; i++ ) { - __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i)); - } - - // perform inverse cipher transformations common for all key sizes - __ BIND(L_common_transform); - for ( int i = 38; i >= 6; i -= 8 ) { - __ aes_dround23(as_FloatRegister(i), F52, F54, F58); - __ aes_dround01(as_FloatRegister(i-2), F52, F54, F56); - if ( i != 6) { - __ aes_dround23(as_FloatRegister(i-4), F56, F58, F54); - __ aes_dround01(as_FloatRegister(i-6), F56, F58, F52); - } else { - __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F54); - __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F52); - } - } - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, O5); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output); - __ delayed()->edge8n(to, G0, O3); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F52, to, 0); - __ retl(); - __ delayed()->stf(FloatRegisterImpl::D, F54, to, 8); - - __ BIND(L_store_misaligned_output); - __ add(to, 8, O4); - __ mov(8, O2); - __ sub(O2, O5, O2); - __ alignaddr(O2, G0, O2); - __ faligndata(F52, F52, F52); - __ faligndata(F54, F54, F54); - __ and3(to, -8, to); - __ and3(O4, -8, O4); - __ stpartialf(to, O3, F52, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(O4, O3, F54, Assembler::ASI_PST8_PRIMARY); - __ add(to, 8, to); - __ add(O4, 8, O4); - __ orn(G0, O3, O3); - __ stpartialf(to, O3, F52, Assembler::ASI_PST8_PRIMARY); - __ retl(); - __ delayed()->stpartialf(O4, O3, F54, Assembler::ASI_PST8_PRIMARY); - - return start; - } - - address generate_cipherBlockChaining_encryptAESCrypt() { - assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0, - "the following code assumes that first element of an int array is aligned to 8 bytes"); - assert((arrayOopDesc::base_offset_in_bytes(T_BYTE) & 7) == 0, - "the following code assumes that first element of a byte array is aligned to 8 bytes"); - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt"); - Label L_cbcenc128, L_load_misaligned_input_128bit, L_128bit_transform, L_store_misaligned_output_128bit; - Label L_check_loop_end_128bit, L_cbcenc192, L_load_misaligned_input_192bit, L_192bit_transform; - Label L_store_misaligned_output_192bit, L_check_loop_end_192bit, L_cbcenc256, L_load_misaligned_input_256bit; - Label L_256bit_transform, L_store_misaligned_output_256bit, L_check_loop_end_256bit; - address start = __ pc(); - Register from = I0; // source byte array - Register to = I1; // destination byte array - Register key = I2; // expanded key array - Register rvec = I3; // init vector - const Register len_reg = I4; // cipher length - const Register keylen = I5; // reg for storing expanded key array length - - __ save_frame(0); - // save cipher len to return in the end - __ mov(len_reg, L0); - - // read expanded key length - __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0); - - // load initial vector, 8-byte alignment is guranteed - __ ldf(FloatRegisterImpl::D, rvec, 0, F60); - __ ldf(FloatRegisterImpl::D, rvec, 8, F62); - // load key, 8-byte alignment is guranteed - __ ldx(key,0,G1); - __ ldx(key,8,G5); - - // start loading expanded key, 8-byte alignment is guranteed - for ( int i = 0, j = 16; i <= 38; i += 2, j += 8 ) { - __ ldf(FloatRegisterImpl::D, key, j, as_FloatRegister(i)); - } - - // 128-bit original key size - __ cmp_and_brx_short(keylen, 44, Assembler::equal, Assembler::pt, L_cbcenc128); - - for ( int i = 40, j = 176; i <= 46; i += 2, j += 8 ) { - __ ldf(FloatRegisterImpl::D, key, j, as_FloatRegister(i)); - } - - // 192-bit original key size - __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pt, L_cbcenc192); - - for ( int i = 48, j = 208; i <= 54; i += 2, j += 8 ) { - __ ldf(FloatRegisterImpl::D, key, j, as_FloatRegister(i)); - } - - // 256-bit original key size - __ ba_short(L_cbcenc256); - - __ align(OptoLoopAlignment); - __ BIND(L_cbcenc128); - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_128bit); - __ delayed()->mov(from, L1); // save original 'from' address before alignaddr - - // aligned case: load input into G3 and G4 - __ ldx(from,0,G3); - __ ldx(from,8,G4); - __ ba_short(L_128bit_transform); - - __ BIND(L_load_misaligned_input_128bit); - // can clobber F48, F50 and F52 as they are not used in 128 and 192-bit key encryption - __ alignaddr(from, G0, from); - __ ldf(FloatRegisterImpl::D, from, 0, F48); - __ ldf(FloatRegisterImpl::D, from, 8, F50); - __ ldf(FloatRegisterImpl::D, from, 16, F52); - __ faligndata(F48, F50, F48); - __ faligndata(F50, F52, F50); - __ movdtox(F48, G3); - __ movdtox(F50, G4); - __ mov(L1, from); - - __ BIND(L_128bit_transform); - __ xor3(G1,G3,G3); - __ xor3(G5,G4,G4); - __ movxtod(G3,F56); - __ movxtod(G4,F58); - __ fxor(FloatRegisterImpl::D, F60, F56, F60); - __ fxor(FloatRegisterImpl::D, F62, F58, F62); - - // TEN_EROUNDS - for ( int i = 0; i <= 32; i += 8 ) { - __ aes_eround01(as_FloatRegister(i), F60, F62, F56); - __ aes_eround23(as_FloatRegister(i+2), F60, F62, F58); - if (i != 32 ) { - __ aes_eround01(as_FloatRegister(i+4), F56, F58, F60); - __ aes_eround23(as_FloatRegister(i+6), F56, F58, F62); - } else { - __ aes_eround01_l(as_FloatRegister(i+4), F56, F58, F60); - __ aes_eround23_l(as_FloatRegister(i+6), F56, F58, F62); - } - } - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, L1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_128bit); - __ delayed()->edge8n(to, G0, L2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F60, to, 0); - __ stf(FloatRegisterImpl::D, F62, to, 8); - __ ba_short(L_check_loop_end_128bit); - - __ BIND(L_store_misaligned_output_128bit); - __ add(to, 8, L3); - __ mov(8, L4); - __ sub(L4, L1, L4); - __ alignaddr(L4, G0, L4); - // save cipher text before circular right shift - // as it needs to be stored as iv for next block (see code before next retl) - __ movdtox(F60, L6); - __ movdtox(F62, L7); - __ faligndata(F60, F60, F60); - __ faligndata(F62, F62, F62); - __ mov(to, L5); - __ and3(to, -8, to); - __ and3(L3, -8, L3); - __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY); - __ add(to, 8, to); - __ add(L3, 8, L3); - __ orn(G0, L2, L2); - __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY); - __ mov(L5, to); - __ movxtod(L6, F60); - __ movxtod(L7, F62); - - __ BIND(L_check_loop_end_128bit); - __ add(from, 16, from); - __ add(to, 16, to); - __ subcc(len_reg, 16, len_reg); - __ br(Assembler::notEqual, false, Assembler::pt, L_cbcenc128); - __ delayed()->nop(); - // re-init intial vector for next block, 8-byte alignment is guaranteed - __ stf(FloatRegisterImpl::D, F60, rvec, 0); - __ stf(FloatRegisterImpl::D, F62, rvec, 8); - __ mov(L0, I0); - __ ret(); - __ delayed()->restore(); - - __ align(OptoLoopAlignment); - __ BIND(L_cbcenc192); - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_192bit); - __ delayed()->mov(from, L1); // save original 'from' address before alignaddr - - // aligned case: load input into G3 and G4 - __ ldx(from,0,G3); - __ ldx(from,8,G4); - __ ba_short(L_192bit_transform); - - __ BIND(L_load_misaligned_input_192bit); - // can clobber F48, F50 and F52 as they are not used in 128 and 192-bit key encryption - __ alignaddr(from, G0, from); - __ ldf(FloatRegisterImpl::D, from, 0, F48); - __ ldf(FloatRegisterImpl::D, from, 8, F50); - __ ldf(FloatRegisterImpl::D, from, 16, F52); - __ faligndata(F48, F50, F48); - __ faligndata(F50, F52, F50); - __ movdtox(F48, G3); - __ movdtox(F50, G4); - __ mov(L1, from); - - __ BIND(L_192bit_transform); - __ xor3(G1,G3,G3); - __ xor3(G5,G4,G4); - __ movxtod(G3,F56); - __ movxtod(G4,F58); - __ fxor(FloatRegisterImpl::D, F60, F56, F60); - __ fxor(FloatRegisterImpl::D, F62, F58, F62); - - // TWELEVE_EROUNDS - for ( int i = 0; i <= 40; i += 8 ) { - __ aes_eround01(as_FloatRegister(i), F60, F62, F56); - __ aes_eround23(as_FloatRegister(i+2), F60, F62, F58); - if (i != 40 ) { - __ aes_eround01(as_FloatRegister(i+4), F56, F58, F60); - __ aes_eround23(as_FloatRegister(i+6), F56, F58, F62); - } else { - __ aes_eround01_l(as_FloatRegister(i+4), F56, F58, F60); - __ aes_eround23_l(as_FloatRegister(i+6), F56, F58, F62); - } - } - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, L1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_192bit); - __ delayed()->edge8n(to, G0, L2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F60, to, 0); - __ stf(FloatRegisterImpl::D, F62, to, 8); - __ ba_short(L_check_loop_end_192bit); - - __ BIND(L_store_misaligned_output_192bit); - __ add(to, 8, L3); - __ mov(8, L4); - __ sub(L4, L1, L4); - __ alignaddr(L4, G0, L4); - __ movdtox(F60, L6); - __ movdtox(F62, L7); - __ faligndata(F60, F60, F60); - __ faligndata(F62, F62, F62); - __ mov(to, L5); - __ and3(to, -8, to); - __ and3(L3, -8, L3); - __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY); - __ add(to, 8, to); - __ add(L3, 8, L3); - __ orn(G0, L2, L2); - __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY); - __ mov(L5, to); - __ movxtod(L6, F60); - __ movxtod(L7, F62); - - __ BIND(L_check_loop_end_192bit); - __ add(from, 16, from); - __ subcc(len_reg, 16, len_reg); - __ add(to, 16, to); - __ br(Assembler::notEqual, false, Assembler::pt, L_cbcenc192); - __ delayed()->nop(); - // re-init intial vector for next block, 8-byte alignment is guaranteed - __ stf(FloatRegisterImpl::D, F60, rvec, 0); - __ stf(FloatRegisterImpl::D, F62, rvec, 8); - __ mov(L0, I0); - __ ret(); - __ delayed()->restore(); - - __ align(OptoLoopAlignment); - __ BIND(L_cbcenc256); - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_256bit); - __ delayed()->mov(from, L1); // save original 'from' address before alignaddr - - // aligned case: load input into G3 and G4 - __ ldx(from,0,G3); - __ ldx(from,8,G4); - __ ba_short(L_256bit_transform); - - __ BIND(L_load_misaligned_input_256bit); - // cannot clobber F48, F50 and F52. F56, F58 can be used though - __ alignaddr(from, G0, from); - __ movdtox(F60, L2); // save F60 before overwriting - __ ldf(FloatRegisterImpl::D, from, 0, F56); - __ ldf(FloatRegisterImpl::D, from, 8, F58); - __ ldf(FloatRegisterImpl::D, from, 16, F60); - __ faligndata(F56, F58, F56); - __ faligndata(F58, F60, F58); - __ movdtox(F56, G3); - __ movdtox(F58, G4); - __ mov(L1, from); - __ movxtod(L2, F60); - - __ BIND(L_256bit_transform); - __ xor3(G1,G3,G3); - __ xor3(G5,G4,G4); - __ movxtod(G3,F56); - __ movxtod(G4,F58); - __ fxor(FloatRegisterImpl::D, F60, F56, F60); - __ fxor(FloatRegisterImpl::D, F62, F58, F62); - - // FOURTEEN_EROUNDS - for ( int i = 0; i <= 48; i += 8 ) { - __ aes_eround01(as_FloatRegister(i), F60, F62, F56); - __ aes_eround23(as_FloatRegister(i+2), F60, F62, F58); - if (i != 48 ) { - __ aes_eround01(as_FloatRegister(i+4), F56, F58, F60); - __ aes_eround23(as_FloatRegister(i+6), F56, F58, F62); - } else { - __ aes_eround01_l(as_FloatRegister(i+4), F56, F58, F60); - __ aes_eround23_l(as_FloatRegister(i+6), F56, F58, F62); - } - } - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, L1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_256bit); - __ delayed()->edge8n(to, G0, L2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F60, to, 0); - __ stf(FloatRegisterImpl::D, F62, to, 8); - __ ba_short(L_check_loop_end_256bit); - - __ BIND(L_store_misaligned_output_256bit); - __ add(to, 8, L3); - __ mov(8, L4); - __ sub(L4, L1, L4); - __ alignaddr(L4, G0, L4); - __ movdtox(F60, L6); - __ movdtox(F62, L7); - __ faligndata(F60, F60, F60); - __ faligndata(F62, F62, F62); - __ mov(to, L5); - __ and3(to, -8, to); - __ and3(L3, -8, L3); - __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY); - __ add(to, 8, to); - __ add(L3, 8, L3); - __ orn(G0, L2, L2); - __ stpartialf(to, L2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(L3, L2, F62, Assembler::ASI_PST8_PRIMARY); - __ mov(L5, to); - __ movxtod(L6, F60); - __ movxtod(L7, F62); - - __ BIND(L_check_loop_end_256bit); - __ add(from, 16, from); - __ subcc(len_reg, 16, len_reg); - __ add(to, 16, to); - __ br(Assembler::notEqual, false, Assembler::pt, L_cbcenc256); - __ delayed()->nop(); - // re-init intial vector for next block, 8-byte alignment is guaranteed - __ stf(FloatRegisterImpl::D, F60, rvec, 0); - __ stf(FloatRegisterImpl::D, F62, rvec, 8); - __ mov(L0, I0); - __ ret(); - __ delayed()->restore(); - - return start; - } - - address generate_cipherBlockChaining_decryptAESCrypt_Parallel() { - assert((arrayOopDesc::base_offset_in_bytes(T_INT) & 7) == 0, - "the following code assumes that first element of an int array is aligned to 8 bytes"); - assert((arrayOopDesc::base_offset_in_bytes(T_BYTE) & 7) == 0, - "the following code assumes that first element of a byte array is aligned to 8 bytes"); - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt"); - Label L_cbcdec_end, L_expand192bit, L_expand256bit, L_dec_first_block_start; - Label L_dec_first_block128, L_dec_first_block192, L_dec_next2_blocks128, L_dec_next2_blocks192, L_dec_next2_blocks256; - Label L_load_misaligned_input_first_block, L_transform_first_block, L_load_misaligned_next2_blocks128, L_transform_next2_blocks128; - Label L_load_misaligned_next2_blocks192, L_transform_next2_blocks192, L_load_misaligned_next2_blocks256, L_transform_next2_blocks256; - Label L_store_misaligned_output_first_block, L_check_decrypt_end, L_store_misaligned_output_next2_blocks128; - Label L_check_decrypt_loop_end128, L_store_misaligned_output_next2_blocks192, L_check_decrypt_loop_end192; - Label L_store_misaligned_output_next2_blocks256, L_check_decrypt_loop_end256; - address start = __ pc(); - Register from = I0; // source byte array - Register to = I1; // destination byte array - Register key = I2; // expanded key array - Register rvec = I3; // init vector - const Register len_reg = I4; // cipher length - const Register original_key = I5; // original key array only required during decryption - const Register keylen = L6; // reg for storing expanded key array length - - __ save_frame(0); //args are read from I* registers since we save the frame in the beginning - // save cipher len to return in the end - __ mov(len_reg, L7); - - // load original key from SunJCE expanded decryption key - // Since we load original key buffer starting first element, 8-byte alignment is guaranteed - for ( int i = 0; i <= 3; i++ ) { - __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i)); - } - - // load initial vector, 8-byte alignment is guaranteed - __ ldx(rvec,0,L0); - __ ldx(rvec,8,L1); - - // read expanded key array length - __ ldsw(Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)), keylen, 0); - - // 256-bit original key size - __ cmp_and_brx_short(keylen, 60, Assembler::equal, Assembler::pn, L_expand256bit); - - // 192-bit original key size - __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_expand192bit); - - // 128-bit original key size - // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions - for ( int i = 0; i <= 36; i += 4 ) { - __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+2), i/4, as_FloatRegister(i+4)); - __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+4), as_FloatRegister(i+6)); - } - - // load expanded key[last-1] and key[last] elements - __ movdtox(F40,L2); - __ movdtox(F42,L3); - - __ and3(len_reg, 16, L4); - __ br_null_short(L4, Assembler::pt, L_dec_next2_blocks128); - __ nop(); - - __ ba_short(L_dec_first_block_start); - - __ BIND(L_expand192bit); - // load rest of the 192-bit key - __ ldf(FloatRegisterImpl::S, original_key, 16, F4); - __ ldf(FloatRegisterImpl::S, original_key, 20, F5); - - // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions - for ( int i = 0; i <= 36; i += 6 ) { - __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+4), i/6, as_FloatRegister(i+6)); - __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+6), as_FloatRegister(i+8)); - __ aes_kexpand2(as_FloatRegister(i+4), as_FloatRegister(i+8), as_FloatRegister(i+10)); - } - __ aes_kexpand1(F42, F46, 7, F48); - __ aes_kexpand2(F44, F48, F50); - - // load expanded key[last-1] and key[last] elements - __ movdtox(F48,L2); - __ movdtox(F50,L3); - - __ and3(len_reg, 16, L4); - __ br_null_short(L4, Assembler::pt, L_dec_next2_blocks192); - __ nop(); - - __ ba_short(L_dec_first_block_start); - - __ BIND(L_expand256bit); - // load rest of the 256-bit key - for ( int i = 4; i <= 7; i++ ) { - __ ldf(FloatRegisterImpl::S, original_key, i*4, as_FloatRegister(i)); - } - - // perform key expansion since SunJCE decryption-key expansion is not compatible with SPARC crypto instructions - for ( int i = 0; i <= 40; i += 8 ) { - __ aes_kexpand1(as_FloatRegister(i), as_FloatRegister(i+6), i/8, as_FloatRegister(i+8)); - __ aes_kexpand2(as_FloatRegister(i+2), as_FloatRegister(i+8), as_FloatRegister(i+10)); - __ aes_kexpand0(as_FloatRegister(i+4), as_FloatRegister(i+10), as_FloatRegister(i+12)); - __ aes_kexpand2(as_FloatRegister(i+6), as_FloatRegister(i+12), as_FloatRegister(i+14)); - } - __ aes_kexpand1(F48, F54, 6, F56); - __ aes_kexpand2(F50, F56, F58); - - // load expanded key[last-1] and key[last] elements - __ movdtox(F56,L2); - __ movdtox(F58,L3); - - __ and3(len_reg, 16, L4); - __ br_null_short(L4, Assembler::pt, L_dec_next2_blocks256); - - __ BIND(L_dec_first_block_start); - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_input_first_block); - __ delayed()->mov(from, G1); // save original 'from' address before alignaddr - - // aligned case: load input into L4 and L5 - __ ldx(from,0,L4); - __ ldx(from,8,L5); - __ ba_short(L_transform_first_block); - - __ BIND(L_load_misaligned_input_first_block); - __ alignaddr(from, G0, from); - // F58, F60, F62 can be clobbered - __ ldf(FloatRegisterImpl::D, from, 0, F58); - __ ldf(FloatRegisterImpl::D, from, 8, F60); - __ ldf(FloatRegisterImpl::D, from, 16, F62); - __ faligndata(F58, F60, F58); - __ faligndata(F60, F62, F60); - __ movdtox(F58, L4); - __ movdtox(F60, L5); - __ mov(G1, from); - - __ BIND(L_transform_first_block); - __ xor3(L2,L4,G1); - __ movxtod(G1,F60); - __ xor3(L3,L5,G1); - __ movxtod(G1,F62); - - // 128-bit original key size - __ cmp_and_brx_short(keylen, 44, Assembler::equal, Assembler::pn, L_dec_first_block128); - - // 192-bit original key size - __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_dec_first_block192); - - __ aes_dround23(F54, F60, F62, F58); - __ aes_dround01(F52, F60, F62, F56); - __ aes_dround23(F50, F56, F58, F62); - __ aes_dround01(F48, F56, F58, F60); - - __ BIND(L_dec_first_block192); - __ aes_dround23(F46, F60, F62, F58); - __ aes_dround01(F44, F60, F62, F56); - __ aes_dround23(F42, F56, F58, F62); - __ aes_dround01(F40, F56, F58, F60); - - __ BIND(L_dec_first_block128); - for ( int i = 38; i >= 6; i -= 8 ) { - __ aes_dround23(as_FloatRegister(i), F60, F62, F58); - __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56); - if ( i != 6) { - __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60); - } else { - __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F60); - } - } - - __ movxtod(L0,F56); - __ movxtod(L1,F58); - __ mov(L4,L0); - __ mov(L5,L1); - __ fxor(FloatRegisterImpl::D, F56, F60, F60); - __ fxor(FloatRegisterImpl::D, F58, F62, F62); - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, G1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_first_block); - __ delayed()->edge8n(to, G0, G2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F60, to, 0); - __ stf(FloatRegisterImpl::D, F62, to, 8); - __ ba_short(L_check_decrypt_end); - - __ BIND(L_store_misaligned_output_first_block); - __ add(to, 8, G3); - __ mov(8, G4); - __ sub(G4, G1, G4); - __ alignaddr(G4, G0, G4); - __ faligndata(F60, F60, F60); - __ faligndata(F62, F62, F62); - __ mov(to, G1); - __ and3(to, -8, to); - __ and3(G3, -8, G3); - __ stpartialf(to, G2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(G3, G2, F62, Assembler::ASI_PST8_PRIMARY); - __ add(to, 8, to); - __ add(G3, 8, G3); - __ orn(G0, G2, G2); - __ stpartialf(to, G2, F60, Assembler::ASI_PST8_PRIMARY); - __ stpartialf(G3, G2, F62, Assembler::ASI_PST8_PRIMARY); - __ mov(G1, to); - - __ BIND(L_check_decrypt_end); - __ add(from, 16, from); - __ add(to, 16, to); - __ subcc(len_reg, 16, len_reg); - __ br(Assembler::equal, false, Assembler::pt, L_cbcdec_end); - __ delayed()->nop(); - - // 256-bit original key size - __ cmp_and_brx_short(keylen, 60, Assembler::equal, Assembler::pn, L_dec_next2_blocks256); - - // 192-bit original key size - __ cmp_and_brx_short(keylen, 52, Assembler::equal, Assembler::pn, L_dec_next2_blocks192); - - __ align(OptoLoopAlignment); - __ BIND(L_dec_next2_blocks128); - __ nop(); - - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_next2_blocks128); - __ delayed()->mov(from, G1); // save original 'from' address before alignaddr - - // aligned case: load input into G4, G5, L4 and L5 - __ ldx(from,0,G4); - __ ldx(from,8,G5); - __ ldx(from,16,L4); - __ ldx(from,24,L5); - __ ba_short(L_transform_next2_blocks128); - - __ BIND(L_load_misaligned_next2_blocks128); - __ alignaddr(from, G0, from); - // F40, F42, F58, F60, F62 can be clobbered - __ ldf(FloatRegisterImpl::D, from, 0, F40); - __ ldf(FloatRegisterImpl::D, from, 8, F42); - __ ldf(FloatRegisterImpl::D, from, 16, F60); - __ ldf(FloatRegisterImpl::D, from, 24, F62); - __ ldf(FloatRegisterImpl::D, from, 32, F58); - __ faligndata(F40, F42, F40); - __ faligndata(F42, F60, F42); - __ faligndata(F60, F62, F60); - __ faligndata(F62, F58, F62); - __ movdtox(F40, G4); - __ movdtox(F42, G5); - __ movdtox(F60, L4); - __ movdtox(F62, L5); - __ mov(G1, from); - - __ BIND(L_transform_next2_blocks128); - // F40:F42 used for first 16-bytes - __ xor3(L2,G4,G1); - __ movxtod(G1,F40); - __ xor3(L3,G5,G1); - __ movxtod(G1,F42); - - // F60:F62 used for next 16-bytes - __ xor3(L2,L4,G1); - __ movxtod(G1,F60); - __ xor3(L3,L5,G1); - __ movxtod(G1,F62); - - for ( int i = 38; i >= 6; i -= 8 ) { - __ aes_dround23(as_FloatRegister(i), F40, F42, F44); - __ aes_dround01(as_FloatRegister(i-2), F40, F42, F46); - __ aes_dround23(as_FloatRegister(i), F60, F62, F58); - __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56); - if (i != 6 ) { - __ aes_dround23(as_FloatRegister(i-4), F46, F44, F42); - __ aes_dround01(as_FloatRegister(i-6), F46, F44, F40); - __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60); - } else { - __ aes_dround23_l(as_FloatRegister(i-4), F46, F44, F42); - __ aes_dround01_l(as_FloatRegister(i-6), F46, F44, F40); - __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F60); - } - } - - __ movxtod(L0,F46); - __ movxtod(L1,F44); - __ fxor(FloatRegisterImpl::D, F46, F40, F40); - __ fxor(FloatRegisterImpl::D, F44, F42, F42); - - __ movxtod(G4,F56); - __ movxtod(G5,F58); - __ mov(L4,L0); - __ mov(L5,L1); - __ fxor(FloatRegisterImpl::D, F56, F60, F60); - __ fxor(FloatRegisterImpl::D, F58, F62, F62); - - // For mis-aligned store of 32 bytes of result we can do: - // Circular right-shift all 4 FP registers so that 'head' and 'tail' - // parts that need to be stored starting at mis-aligned address are in a FP reg - // the other 3 FP regs can thus be stored using regular store - // we then use the edge + partial-store mechanism to store the 'head' and 'tail' parts - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, G1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_next2_blocks128); - __ delayed()->edge8n(to, G0, G2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F40, to, 0); - __ stf(FloatRegisterImpl::D, F42, to, 8); - __ stf(FloatRegisterImpl::D, F60, to, 16); - __ stf(FloatRegisterImpl::D, F62, to, 24); - __ ba_short(L_check_decrypt_loop_end128); - - __ BIND(L_store_misaligned_output_next2_blocks128); - __ mov(8, G4); - __ sub(G4, G1, G4); - __ alignaddr(G4, G0, G4); - __ faligndata(F40, F42, F56); // F56 can be clobbered - __ faligndata(F42, F60, F42); - __ faligndata(F60, F62, F60); - __ faligndata(F62, F40, F40); - __ mov(to, G1); - __ and3(to, -8, to); - __ stpartialf(to, G2, F40, Assembler::ASI_PST8_PRIMARY); - __ stf(FloatRegisterImpl::D, F56, to, 8); - __ stf(FloatRegisterImpl::D, F42, to, 16); - __ stf(FloatRegisterImpl::D, F60, to, 24); - __ add(to, 32, to); - __ orn(G0, G2, G2); - __ stpartialf(to, G2, F40, Assembler::ASI_PST8_PRIMARY); - __ mov(G1, to); - - __ BIND(L_check_decrypt_loop_end128); - __ add(from, 32, from); - __ add(to, 32, to); - __ subcc(len_reg, 32, len_reg); - __ br(Assembler::notEqual, false, Assembler::pt, L_dec_next2_blocks128); - __ delayed()->nop(); - __ ba_short(L_cbcdec_end); - - __ align(OptoLoopAlignment); - __ BIND(L_dec_next2_blocks192); - __ nop(); - - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_next2_blocks192); - __ delayed()->mov(from, G1); // save original 'from' address before alignaddr - - // aligned case: load input into G4, G5, L4 and L5 - __ ldx(from,0,G4); - __ ldx(from,8,G5); - __ ldx(from,16,L4); - __ ldx(from,24,L5); - __ ba_short(L_transform_next2_blocks192); - - __ BIND(L_load_misaligned_next2_blocks192); - __ alignaddr(from, G0, from); - // F48, F50, F52, F60, F62 can be clobbered - __ ldf(FloatRegisterImpl::D, from, 0, F48); - __ ldf(FloatRegisterImpl::D, from, 8, F50); - __ ldf(FloatRegisterImpl::D, from, 16, F60); - __ ldf(FloatRegisterImpl::D, from, 24, F62); - __ ldf(FloatRegisterImpl::D, from, 32, F52); - __ faligndata(F48, F50, F48); - __ faligndata(F50, F60, F50); - __ faligndata(F60, F62, F60); - __ faligndata(F62, F52, F62); - __ movdtox(F48, G4); - __ movdtox(F50, G5); - __ movdtox(F60, L4); - __ movdtox(F62, L5); - __ mov(G1, from); - - __ BIND(L_transform_next2_blocks192); - // F48:F50 used for first 16-bytes - __ xor3(L2,G4,G1); - __ movxtod(G1,F48); - __ xor3(L3,G5,G1); - __ movxtod(G1,F50); - - // F60:F62 used for next 16-bytes - __ xor3(L2,L4,G1); - __ movxtod(G1,F60); - __ xor3(L3,L5,G1); - __ movxtod(G1,F62); - - for ( int i = 46; i >= 6; i -= 8 ) { - __ aes_dround23(as_FloatRegister(i), F48, F50, F52); - __ aes_dround01(as_FloatRegister(i-2), F48, F50, F54); - __ aes_dround23(as_FloatRegister(i), F60, F62, F58); - __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56); - if (i != 6 ) { - __ aes_dround23(as_FloatRegister(i-4), F54, F52, F50); - __ aes_dround01(as_FloatRegister(i-6), F54, F52, F48); - __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60); - } else { - __ aes_dround23_l(as_FloatRegister(i-4), F54, F52, F50); - __ aes_dround01_l(as_FloatRegister(i-6), F54, F52, F48); - __ aes_dround23_l(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01_l(as_FloatRegister(i-6), F56, F58, F60); - } - } - - __ movxtod(L0,F54); - __ movxtod(L1,F52); - __ fxor(FloatRegisterImpl::D, F54, F48, F48); - __ fxor(FloatRegisterImpl::D, F52, F50, F50); - - __ movxtod(G4,F56); - __ movxtod(G5,F58); - __ mov(L4,L0); - __ mov(L5,L1); - __ fxor(FloatRegisterImpl::D, F56, F60, F60); - __ fxor(FloatRegisterImpl::D, F58, F62, F62); - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, G1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_next2_blocks192); - __ delayed()->edge8n(to, G0, G2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F48, to, 0); - __ stf(FloatRegisterImpl::D, F50, to, 8); - __ stf(FloatRegisterImpl::D, F60, to, 16); - __ stf(FloatRegisterImpl::D, F62, to, 24); - __ ba_short(L_check_decrypt_loop_end192); - - __ BIND(L_store_misaligned_output_next2_blocks192); - __ mov(8, G4); - __ sub(G4, G1, G4); - __ alignaddr(G4, G0, G4); - __ faligndata(F48, F50, F56); // F56 can be clobbered - __ faligndata(F50, F60, F50); - __ faligndata(F60, F62, F60); - __ faligndata(F62, F48, F48); - __ mov(to, G1); - __ and3(to, -8, to); - __ stpartialf(to, G2, F48, Assembler::ASI_PST8_PRIMARY); - __ stf(FloatRegisterImpl::D, F56, to, 8); - __ stf(FloatRegisterImpl::D, F50, to, 16); - __ stf(FloatRegisterImpl::D, F60, to, 24); - __ add(to, 32, to); - __ orn(G0, G2, G2); - __ stpartialf(to, G2, F48, Assembler::ASI_PST8_PRIMARY); - __ mov(G1, to); - - __ BIND(L_check_decrypt_loop_end192); - __ add(from, 32, from); - __ add(to, 32, to); - __ subcc(len_reg, 32, len_reg); - __ br(Assembler::notEqual, false, Assembler::pt, L_dec_next2_blocks192); - __ delayed()->nop(); - __ ba_short(L_cbcdec_end); - - __ align(OptoLoopAlignment); - __ BIND(L_dec_next2_blocks256); - __ nop(); - - // check for 8-byte alignment since source byte array may have an arbitrary alignment if offset mod 8 is non-zero - __ andcc(from, 7, G0); - __ br(Assembler::notZero, true, Assembler::pn, L_load_misaligned_next2_blocks256); - __ delayed()->mov(from, G1); // save original 'from' address before alignaddr - - // aligned case: load input into G4, G5, L4 and L5 - __ ldx(from,0,G4); - __ ldx(from,8,G5); - __ ldx(from,16,L4); - __ ldx(from,24,L5); - __ ba_short(L_transform_next2_blocks256); - - __ BIND(L_load_misaligned_next2_blocks256); - __ alignaddr(from, G0, from); - // F0, F2, F4, F60, F62 can be clobbered - __ ldf(FloatRegisterImpl::D, from, 0, F0); - __ ldf(FloatRegisterImpl::D, from, 8, F2); - __ ldf(FloatRegisterImpl::D, from, 16, F60); - __ ldf(FloatRegisterImpl::D, from, 24, F62); - __ ldf(FloatRegisterImpl::D, from, 32, F4); - __ faligndata(F0, F2, F0); - __ faligndata(F2, F60, F2); - __ faligndata(F60, F62, F60); - __ faligndata(F62, F4, F62); - __ movdtox(F0, G4); - __ movdtox(F2, G5); - __ movdtox(F60, L4); - __ movdtox(F62, L5); - __ mov(G1, from); - - __ BIND(L_transform_next2_blocks256); - // F0:F2 used for first 16-bytes - __ xor3(L2,G4,G1); - __ movxtod(G1,F0); - __ xor3(L3,G5,G1); - __ movxtod(G1,F2); - - // F60:F62 used for next 16-bytes - __ xor3(L2,L4,G1); - __ movxtod(G1,F60); - __ xor3(L3,L5,G1); - __ movxtod(G1,F62); - - __ aes_dround23(F54, F0, F2, F4); - __ aes_dround01(F52, F0, F2, F6); - __ aes_dround23(F54, F60, F62, F58); - __ aes_dround01(F52, F60, F62, F56); - __ aes_dround23(F50, F6, F4, F2); - __ aes_dround01(F48, F6, F4, F0); - __ aes_dround23(F50, F56, F58, F62); - __ aes_dround01(F48, F56, F58, F60); - // save F48:F54 in temp registers - __ movdtox(F54,G2); - __ movdtox(F52,G3); - __ movdtox(F50,L6); - __ movdtox(F48,G1); - for ( int i = 46; i >= 14; i -= 8 ) { - __ aes_dround23(as_FloatRegister(i), F0, F2, F4); - __ aes_dround01(as_FloatRegister(i-2), F0, F2, F6); - __ aes_dround23(as_FloatRegister(i), F60, F62, F58); - __ aes_dround01(as_FloatRegister(i-2), F60, F62, F56); - __ aes_dround23(as_FloatRegister(i-4), F6, F4, F2); - __ aes_dround01(as_FloatRegister(i-6), F6, F4, F0); - __ aes_dround23(as_FloatRegister(i-4), F56, F58, F62); - __ aes_dround01(as_FloatRegister(i-6), F56, F58, F60); - } - // init F48:F54 with F0:F6 values (original key) - __ ldf(FloatRegisterImpl::D, original_key, 0, F48); - __ ldf(FloatRegisterImpl::D, original_key, 8, F50); - __ ldf(FloatRegisterImpl::D, original_key, 16, F52); - __ ldf(FloatRegisterImpl::D, original_key, 24, F54); - __ aes_dround23(F54, F0, F2, F4); - __ aes_dround01(F52, F0, F2, F6); - __ aes_dround23(F54, F60, F62, F58); - __ aes_dround01(F52, F60, F62, F56); - __ aes_dround23_l(F50, F6, F4, F2); - __ aes_dround01_l(F48, F6, F4, F0); - __ aes_dround23_l(F50, F56, F58, F62); - __ aes_dround01_l(F48, F56, F58, F60); - // re-init F48:F54 with their original values - __ movxtod(G2,F54); - __ movxtod(G3,F52); - __ movxtod(L6,F50); - __ movxtod(G1,F48); - - __ movxtod(L0,F6); - __ movxtod(L1,F4); - __ fxor(FloatRegisterImpl::D, F6, F0, F0); - __ fxor(FloatRegisterImpl::D, F4, F2, F2); - - __ movxtod(G4,F56); - __ movxtod(G5,F58); - __ mov(L4,L0); - __ mov(L5,L1); - __ fxor(FloatRegisterImpl::D, F56, F60, F60); - __ fxor(FloatRegisterImpl::D, F58, F62, F62); - - // check for 8-byte alignment since dest byte array may have arbitrary alignment if offset mod 8 is non-zero - __ andcc(to, 7, G1); - __ br(Assembler::notZero, true, Assembler::pn, L_store_misaligned_output_next2_blocks256); - __ delayed()->edge8n(to, G0, G2); - - // aligned case: store output into the destination array - __ stf(FloatRegisterImpl::D, F0, to, 0); - __ stf(FloatRegisterImpl::D, F2, to, 8); - __ stf(FloatRegisterImpl::D, F60, to, 16); - __ stf(FloatRegisterImpl::D, F62, to, 24); - __ ba_short(L_check_decrypt_loop_end256); - - __ BIND(L_store_misaligned_output_next2_blocks256); - __ mov(8, G4); - __ sub(G4, G1, G4); - __ alignaddr(G4, G0, G4); - __ faligndata(F0, F2, F56); // F56 can be clobbered - __ faligndata(F2, F60, F2); - __ faligndata(F60, F62, F60); - __ faligndata(F62, F0, F0); - __ mov(to, G1); - __ and3(to, -8, to); - __ stpartialf(to, G2, F0, Assembler::ASI_PST8_PRIMARY); - __ stf(FloatRegisterImpl::D, F56, to, 8); - __ stf(FloatRegisterImpl::D, F2, to, 16); - __ stf(FloatRegisterImpl::D, F60, to, 24); - __ add(to, 32, to); - __ orn(G0, G2, G2); - __ stpartialf(to, G2, F0, Assembler::ASI_PST8_PRIMARY); - __ mov(G1, to); - - __ BIND(L_check_decrypt_loop_end256); - __ add(from, 32, from); - __ add(to, 32, to); - __ subcc(len_reg, 32, len_reg); - __ br(Assembler::notEqual, false, Assembler::pt, L_dec_next2_blocks256); - __ delayed()->nop(); - - __ BIND(L_cbcdec_end); - // re-init intial vector for next block, 8-byte alignment is guaranteed - __ stx(L0, rvec, 0); - __ stx(L1, rvec, 8); - __ mov(L7, I0); - __ ret(); - __ delayed()->restore(); - - return start; - } - - address generate_sha1_implCompress(bool multi_block, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_sha1_loop, L_sha1_unaligned_input, L_sha1_unaligned_input_loop; - int i; - - Register buf = O0; // byte[] source+offset - Register state = O1; // int[] SHA.state - Register ofs = O2; // int offset - Register limit = O3; // int limit - - // load state into F0-F4 - for (i = 0; i < 5; i++) { - __ ldf(FloatRegisterImpl::S, state, i*4, as_FloatRegister(i)); - } - - __ andcc(buf, 7, G0); - __ br(Assembler::notZero, false, Assembler::pn, L_sha1_unaligned_input); - __ delayed()->nop(); - - __ BIND(L_sha1_loop); - // load buf into F8-F22 - for (i = 0; i < 8; i++) { - __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8)); - } - __ sha1(); - if (multi_block) { - __ add(ofs, 64, ofs); - __ add(buf, 64, buf); - __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha1_loop); - __ mov(ofs, O0); // to be returned - } - - // store F0-F4 into state and return - for (i = 0; i < 4; i++) { - __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4); - } - __ retl(); - __ delayed()->stf(FloatRegisterImpl::S, F4, state, 0x10); - - __ BIND(L_sha1_unaligned_input); - __ alignaddr(buf, G0, buf); - - __ BIND(L_sha1_unaligned_input_loop); - // load buf into F8-F22 - for (i = 0; i < 9; i++) { - __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8)); - } - for (i = 0; i < 8; i++) { - __ faligndata(as_FloatRegister(i*2 + 8), as_FloatRegister(i*2 + 10), as_FloatRegister(i*2 + 8)); - } - __ sha1(); - if (multi_block) { - __ add(ofs, 64, ofs); - __ add(buf, 64, buf); - __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha1_unaligned_input_loop); - __ mov(ofs, O0); // to be returned - } - - // store F0-F4 into state and return - for (i = 0; i < 4; i++) { - __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4); - } - __ retl(); - __ delayed()->stf(FloatRegisterImpl::S, F4, state, 0x10); - - return start; - } - - address generate_sha256_implCompress(bool multi_block, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_sha256_loop, L_sha256_unaligned_input, L_sha256_unaligned_input_loop; - int i; - - Register buf = O0; // byte[] source+offset - Register state = O1; // int[] SHA2.state - Register ofs = O2; // int offset - Register limit = O3; // int limit - - // load state into F0-F7 - for (i = 0; i < 8; i++) { - __ ldf(FloatRegisterImpl::S, state, i*4, as_FloatRegister(i)); - } - - __ andcc(buf, 7, G0); - __ br(Assembler::notZero, false, Assembler::pn, L_sha256_unaligned_input); - __ delayed()->nop(); - - __ BIND(L_sha256_loop); - // load buf into F8-F22 - for (i = 0; i < 8; i++) { - __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8)); - } - __ sha256(); - if (multi_block) { - __ add(ofs, 64, ofs); - __ add(buf, 64, buf); - __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha256_loop); - __ mov(ofs, O0); // to be returned - } - - // store F0-F7 into state and return - for (i = 0; i < 7; i++) { - __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4); - } - __ retl(); - __ delayed()->stf(FloatRegisterImpl::S, F7, state, 0x1c); - - __ BIND(L_sha256_unaligned_input); - __ alignaddr(buf, G0, buf); - - __ BIND(L_sha256_unaligned_input_loop); - // load buf into F8-F22 - for (i = 0; i < 9; i++) { - __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 8)); - } - for (i = 0; i < 8; i++) { - __ faligndata(as_FloatRegister(i*2 + 8), as_FloatRegister(i*2 + 10), as_FloatRegister(i*2 + 8)); - } - __ sha256(); - if (multi_block) { - __ add(ofs, 64, ofs); - __ add(buf, 64, buf); - __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha256_unaligned_input_loop); - __ mov(ofs, O0); // to be returned - } - - // store F0-F7 into state and return - for (i = 0; i < 7; i++) { - __ stf(FloatRegisterImpl::S, as_FloatRegister(i), state, i*4); - } - __ retl(); - __ delayed()->stf(FloatRegisterImpl::S, F7, state, 0x1c); - - return start; - } - - address generate_sha512_implCompress(bool multi_block, const char *name) { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", name); - address start = __ pc(); - - Label L_sha512_loop, L_sha512_unaligned_input, L_sha512_unaligned_input_loop; - int i; - - Register buf = O0; // byte[] source+offset - Register state = O1; // long[] SHA5.state - Register ofs = O2; // int offset - Register limit = O3; // int limit - - // load state into F0-F14 - for (i = 0; i < 8; i++) { - __ ldf(FloatRegisterImpl::D, state, i*8, as_FloatRegister(i*2)); - } - - __ andcc(buf, 7, G0); - __ br(Assembler::notZero, false, Assembler::pn, L_sha512_unaligned_input); - __ delayed()->nop(); - - __ BIND(L_sha512_loop); - // load buf into F16-F46 - for (i = 0; i < 16; i++) { - __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 16)); - } - __ sha512(); - if (multi_block) { - __ add(ofs, 128, ofs); - __ add(buf, 128, buf); - __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha512_loop); - __ mov(ofs, O0); // to be returned - } - - // store F0-F14 into state and return - for (i = 0; i < 7; i++) { - __ stf(FloatRegisterImpl::D, as_FloatRegister(i*2), state, i*8); - } - __ retl(); - __ delayed()->stf(FloatRegisterImpl::D, F14, state, 0x38); - - __ BIND(L_sha512_unaligned_input); - __ alignaddr(buf, G0, buf); - - __ BIND(L_sha512_unaligned_input_loop); - // load buf into F16-F46 - for (i = 0; i < 17; i++) { - __ ldf(FloatRegisterImpl::D, buf, i*8, as_FloatRegister(i*2 + 16)); - } - for (i = 0; i < 16; i++) { - __ faligndata(as_FloatRegister(i*2 + 16), as_FloatRegister(i*2 + 18), as_FloatRegister(i*2 + 16)); - } - __ sha512(); - if (multi_block) { - __ add(ofs, 128, ofs); - __ add(buf, 128, buf); - __ cmp_and_brx_short(ofs, limit, Assembler::lessEqual, Assembler::pt, L_sha512_unaligned_input_loop); - __ mov(ofs, O0); // to be returned - } - - // store F0-F14 into state and return - for (i = 0; i < 7; i++) { - __ stf(FloatRegisterImpl::D, as_FloatRegister(i*2), state, i*8); - } - __ retl(); - __ delayed()->stf(FloatRegisterImpl::D, F14, state, 0x38); - - return start; - } - - /* Single and multi-block ghash operations */ - address generate_ghash_processBlocks() { - __ align(CodeEntryAlignment); - Label L_ghash_loop, L_aligned, L_main; - StubCodeMark mark(this, "StubRoutines", "ghash_processBlocks"); - address start = __ pc(); - - Register state = I0; - Register subkeyH = I1; - Register data = I2; - Register len = I3; - - __ save_frame(0); - - __ ldx(state, 0, O0); - __ ldx(state, 8, O1); - - // Loop label for multiblock operations - __ BIND(L_ghash_loop); - - // Check if 'data' is unaligned - __ andcc(data, 7, G1); - __ br(Assembler::zero, false, Assembler::pt, L_aligned); - __ delayed()->nop(); - - Register left_shift = L1; - Register right_shift = L2; - Register data_ptr = L3; - - // Get left and right shift values in bits - __ sll(G1, LogBitsPerByte, left_shift); - __ mov(64, right_shift); - __ sub(right_shift, left_shift, right_shift); - - // Align to read 'data' - __ sub(data, G1, data_ptr); - - // Load first 8 bytes of 'data' - __ ldx(data_ptr, 0, O4); - __ sllx(O4, left_shift, O4); - __ ldx(data_ptr, 8, O5); - __ srlx(O5, right_shift, G4); - __ bset(G4, O4); - - // Load second 8 bytes of 'data' - __ sllx(O5, left_shift, O5); - __ ldx(data_ptr, 16, G4); - __ srlx(G4, right_shift, G4); - __ ba(L_main); - __ delayed()->bset(G4, O5); - - // If 'data' is aligned, load normally - __ BIND(L_aligned); - __ ldx(data, 0, O4); - __ ldx(data, 8, O5); - - __ BIND(L_main); - __ ldx(subkeyH, 0, O2); - __ ldx(subkeyH, 8, O3); - - __ xor3(O0, O4, O0); - __ xor3(O1, O5, O1); - - __ xmulxhi(O0, O3, G3); - __ xmulx(O0, O2, O5); - __ xmulxhi(O1, O2, G4); - __ xmulxhi(O1, O3, G5); - __ xmulx(O0, O3, G1); - __ xmulx(O1, O3, G2); - __ xmulx(O1, O2, O3); - __ xmulxhi(O0, O2, O4); - - __ mov(0xE1, O0); - __ sllx(O0, 56, O0); - - __ xor3(O5, G3, O5); - __ xor3(O5, G4, O5); - __ xor3(G5, G1, G1); - __ xor3(G1, O3, G1); - __ srlx(G2, 63, O1); - __ srlx(G1, 63, G3); - __ sllx(G2, 63, O3); - __ sllx(G2, 58, O2); - __ xor3(O3, O2, O2); - - __ sllx(G1, 1, G1); - __ or3(G1, O1, G1); - - __ xor3(G1, O2, G1); - - __ sllx(G2, 1, G2); - - __ xmulxhi(G1, O0, O1); - __ xmulx(G1, O0, O2); - __ xmulxhi(G2, O0, O3); - __ xmulx(G2, O0, G1); - - __ xor3(O4, O1, O4); - __ xor3(O5, O2, O5); - __ xor3(O5, O3, O5); - - __ sllx(O4, 1, O2); - __ srlx(O5, 63, O3); - - __ or3(O2, O3, O0); - - __ sllx(O5, 1, O1); - __ srlx(G1, 63, O2); - __ or3(O1, O2, O1); - __ xor3(O1, G3, O1); - - __ deccc(len); - __ br(Assembler::notZero, true, Assembler::pt, L_ghash_loop); - __ delayed()->add(data, 16, data); - - __ stx(O0, I0, 0); - __ stx(O1, I0, 8); - - __ ret(); - __ delayed()->restore(); - - return start; - } - - /** - * Arguments: - * - * Inputs: - * O0 - int crc - * O1 - byte* buf - * O2 - int len - * O3 - int* table - * - * Output: - * O0 - int crc result - */ - address generate_updateBytesCRC32C() { - assert(UseCRC32CIntrinsics, "need CRC32C instruction"); - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C"); - address start = __ pc(); - - const Register crc = O0; // crc - const Register buf = O1; // source java byte array address - const Register len = O2; // number of bytes - const Register table = O3; // byteTable - - __ kernel_crc32c(crc, buf, len, table); - - __ retl(); - __ delayed()->nop(); - - return start; - } - -#define ADLER32_NUM_TEMPS 16 - - /** - * Arguments: - * - * Inputs: - * O0 - int adler - * O1 - byte* buff - * O2 - int len - * - * Output: - * O0 - int adler result - */ - address generate_updateBytesAdler32() { - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "updateBytesAdler32"); - address start = __ pc(); - - Label L_cleanup_loop, L_cleanup_loop_check; - Label L_main_loop_check, L_main_loop, L_inner_loop, L_inner_loop_check; - Label L_nmax_check_done; - - // Aliases - Register s1 = O0; - Register s2 = O3; - Register buff = O1; - Register len = O2; - Register temp[ADLER32_NUM_TEMPS] = {L0, L1, L2, L3, L4, L5, L6, L7, I0, I1, I2, I3, I4, I5, G3, I7}; - - // Max number of bytes we can process before having to take the mod - // 0x15B0 is 5552 in decimal, the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 - unsigned long NMAX = 0x15B0; - - // Zero-out the upper bits of len - __ clruwu(len); - - // Create the mask 0xFFFF - __ set64(0x00FFFF, O4, O5); // O5 is the temp register - - // s1 is initialized to the lower 16 bits of adler - // s2 is initialized to the upper 16 bits of adler - __ srlx(O0, 16, O5); // adler >> 16 - __ and3(O0, O4, s1); // s1 = (adler & 0xFFFF) - __ and3(O5, O4, s2); // s2 = ((adler >> 16) & 0xFFFF) - - // The pipelined loop needs at least 16 elements for 1 iteration - // It does check this, but it is more effective to skip to the cleanup loop - // Setup the constant for cutoff checking - __ mov(15, O4); - - // Check if we are above the cutoff, if not go to the cleanup loop immediately - __ cmp_and_br_short(len, O4, Assembler::lessEqualUnsigned, Assembler::pt, L_cleanup_loop_check); - - // Free up some registers for our use - for (int i = 0; i < ADLER32_NUM_TEMPS; i++) { - __ movxtod(temp[i], as_FloatRegister(2*i)); - } - - // Loop maintenance stuff is done at the end of the loop, so skip to there - __ ba_short(L_main_loop_check); - - __ BIND(L_main_loop); - - // Prologue for inner loop - __ ldub(buff, 0, L0); - __ dec(O5); - - for (int i = 1; i < 8; i++) { - __ ldub(buff, i, temp[i]); - } - - __ inc(buff, 8); - - // Inner loop processes 16 elements at a time, might never execute if only 16 elements - // to be processed by the outter loop - __ ba_short(L_inner_loop_check); - - __ BIND(L_inner_loop); - - for (int i = 0; i < 8; i++) { - __ ldub(buff, (2*i), temp[(8+(2*i)) % ADLER32_NUM_TEMPS]); - __ add(s1, temp[i], s1); - __ ldub(buff, (2*i)+1, temp[(8+(2*i)+1) % ADLER32_NUM_TEMPS]); - __ add(s2, s1, s2); - } - - // Original temp 0-7 used and new loads to temp 0-7 issued - // temp 8-15 ready to be consumed - __ add(s1, I0, s1); - __ dec(O5); - __ add(s2, s1, s2); - __ add(s1, I1, s1); - __ inc(buff, 16); - __ add(s2, s1, s2); - - for (int i = 0; i < 6; i++) { - __ add(s1, temp[10+i], s1); - __ add(s2, s1, s2); - } - - __ BIND(L_inner_loop_check); - __ nop(); - __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_inner_loop); - - // Epilogue - for (int i = 0; i < 4; i++) { - __ ldub(buff, (2*i), temp[8+(2*i)]); - __ add(s1, temp[i], s1); - __ ldub(buff, (2*i)+1, temp[8+(2*i)+1]); - __ add(s2, s1, s2); - } - - __ add(s1, temp[4], s1); - __ inc(buff, 8); - - for (int i = 0; i < 11; i++) { - __ add(s2, s1, s2); - __ add(s1, temp[5+i], s1); - } - - __ add(s2, s1, s2); - - // Take the mod for s1 and s2 - __ set64(0xFFF1, L0, L1); - __ udivx(s1, L0, L1); - __ udivx(s2, L0, L2); - __ mulx(L0, L1, L1); - __ mulx(L0, L2, L2); - __ sub(s1, L1, s1); - __ sub(s2, L2, s2); - - // Make sure there is something left to process - __ BIND(L_main_loop_check); - __ set64(NMAX, L0, L1); - // k = len < NMAX ? len : NMAX - __ cmp_and_br_short(len, L0, Assembler::greaterEqualUnsigned, Assembler::pt, L_nmax_check_done); - __ andn(len, 0x0F, L0); // only loop a multiple of 16 times - __ BIND(L_nmax_check_done); - __ mov(L0, O5); - __ sub(len, L0, len); // len -= k - - __ srlx(O5, 4, O5); // multiplies of 16 - __ cmp_and_br_short(O5, 0, Assembler::notEqual, Assembler::pt, L_main_loop); - - // Restore anything we used, take the mod one last time, combine and return - // Restore any registers we saved - for (int i = 0; i < ADLER32_NUM_TEMPS; i++) { - __ movdtox(as_FloatRegister(2*i), temp[i]); - } - - // There might be nothing left to process - __ ba_short(L_cleanup_loop_check); - - __ BIND(L_cleanup_loop); - __ ldub(buff, 0, O4); // load single byte form buffer - __ inc(buff); // buff++ - __ add(s1, O4, s1); // s1 += *buff++; - __ dec(len); // len-- - __ add(s1, s2, s2); // s2 += s1; - __ BIND(L_cleanup_loop_check); - __ nop(); - __ cmp_and_br_short(len, 0, Assembler::notEqual, Assembler::pt, L_cleanup_loop); - - // Take the mod one last time - __ set64(0xFFF1, O1, O2); - __ udivx(s1, O1, O2); - __ udivx(s2, O1, O5); - __ mulx(O1, O2, O2); - __ mulx(O1, O5, O5); - __ sub(s1, O2, s1); - __ sub(s2, O5, s2); - - // Combine lower bits and higher bits - __ sllx(s2, 16, s2); // s2 = s2 << 16 - __ or3(s1, s2, s1); // adler = s2 | s1 - // Final return value is in O0 - __ retl(); - __ delayed()->nop(); - - return start; - } - - /** - * Arguments: - * - * Inputs: - * O0 - int crc - * O1 - byte* buf - * O2 - int len - * O3 - int* table - * - * Output: - * O0 - int crc result - */ - address generate_updateBytesCRC32() { - assert(UseCRC32Intrinsics, "need VIS3 instructions"); - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32"); - address start = __ pc(); - - const Register crc = O0; // crc - const Register buf = O1; // source java byte array address - const Register len = O2; // length - const Register table = O3; // crc_table address (reuse register) - - __ kernel_crc32(crc, buf, len, table); - - __ retl(); - __ delayed()->nop(); - - return start; - } - - /** - * Arguments: - * - * Inputs: - * I0 - int* x-addr - * I1 - int x-len - * I2 - int* y-addr - * I3 - int y-len - * I4 - int* z-addr (output vector) - * I5 - int z-len - */ - address generate_multiplyToLen() { - assert(UseMultiplyToLenIntrinsic, "need VIS3 instructions"); - - __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); - address start = __ pc(); - - __ save_frame(0); - - const Register xptr = I0; // input address - const Register xlen = I1; // ...and length in 32b-words - const Register yptr = I2; // - const Register ylen = I3; // - const Register zptr = I4; // output address - const Register zlen = I5; // ...and length in 32b-words - - /* The minimal "limb" representation suggest that odd length vectors are as - * likely as even length dittos. This in turn suggests that we need to cope - * with odd/even length arrays and data not aligned properly for 64-bit read - * and write operations. We thus use a number of different kernels: - * - * if (is_even(x.len) && is_even(y.len)) - * if (is_align64(x) && is_align64(y) && is_align64(z)) - * if (x.len == y.len && 16 <= x.len && x.len <= 64) - * memv_mult_mpmul(...) - * else - * memv_mult_64x64(...) - * else - * memv_mult_64x64u(...) - * else - * memv_mult_32x32(...) - * - * Here we assume VIS3 support (for 'umulxhi', 'addxc' and 'addxccc'). - * In case CBCOND instructions are supported, we will use 'cxbX'. If the - * MPMUL instruction is supported, we will generate a kernel using 'mpmul' - * (for vectors with proper characteristics). - */ - const Register tmp0 = L0; - const Register tmp1 = L1; - - Label L_mult_32x32; - Label L_mult_64x64u; - Label L_mult_64x64; - Label L_exit; - - if_both_even(xlen, ylen, tmp0, false, L_mult_32x32); - if_all3_aligned(xptr, yptr, zptr, tmp1, 64, false, L_mult_64x64u); - - if (UseMPMUL) { - if_eq(xlen, ylen, false, L_mult_64x64); - if_in_rng(xlen, 16, 64, tmp0, tmp1, false, L_mult_64x64); - - // 1. Multiply naturally aligned 64b-datums using a generic 'mpmul' kernel, - // operating on equal length vectors of size [16..64]. - gen_mult_mpmul(xlen, xptr, yptr, zptr, L_exit); - } - - // 2. Multiply naturally aligned 64-bit datums (64x64). - __ bind(L_mult_64x64); - gen_mult_64x64(xptr, xlen, yptr, ylen, zptr, zlen, L_exit); - - // 3. Multiply unaligned 64-bit datums (64x64). - __ bind(L_mult_64x64u); - gen_mult_64x64_unaligned(xptr, xlen, yptr, ylen, zptr, zlen, L_exit); - - // 4. Multiply naturally aligned 32-bit datums (32x32). - __ bind(L_mult_32x32); - gen_mult_32x32(xptr, xlen, yptr, ylen, zptr, zlen, L_exit); - - __ bind(L_exit); - __ ret(); - __ delayed()->restore(); - - return start; - } - - // Additional help functions used by multiplyToLen generation. - - void if_both_even(Register r1, Register r2, Register tmp, bool iseven, Label &L) - { - __ or3(r1, r2, tmp); - __ andcc(tmp, 0x1, tmp); - __ br_icc_zero(iseven, Assembler::pn, L); - } - - void if_all3_aligned(Register r1, Register r2, Register r3, - Register tmp, uint align, bool isalign, Label &L) - { - __ or3(r1, r2, tmp); - __ or3(r3, tmp, tmp); - __ andcc(tmp, (align - 1), tmp); - __ br_icc_zero(isalign, Assembler::pn, L); - } - - void if_eq(Register x, Register y, bool iseq, Label &L) - { - Assembler::Condition cf = (iseq ? Assembler::equal : Assembler::notEqual); - __ cmp_and_br_short(x, y, cf, Assembler::pt, L); - } - - void if_in_rng(Register x, int lb, int ub, Register t1, Register t2, bool inrng, Label &L) - { - assert(Assembler::is_simm13(lb), "Small ints only!"); - assert(Assembler::is_simm13(ub), "Small ints only!"); - // Compute (x - lb) * (ub - x) >= 0 - // NOTE: With the local use of this routine, we rely on small integers to - // guarantee that we do not overflow in the multiplication. - __ add(G0, ub, t2); - __ sub(x, lb, t1); - __ sub(t2, x, t2); - __ mulx(t1, t2, t1); - Assembler::Condition cf = (inrng ? Assembler::greaterEqual : Assembler::less); - __ cmp_and_br_short(t1, G0, cf, Assembler::pt, L); - } - - void ldd_entry(Register base, Register offs, FloatRegister dest) - { - __ ldd(base, offs, dest); - __ inc(offs, 8); - } - - void ldx_entry(Register base, Register offs, Register dest) - { - __ ldx(base, offs, dest); - __ inc(offs, 8); - } - - void mpmul_entry(int m, Label &next) - { - __ mpmul(m); - __ cbcond(Assembler::equal, Assembler::icc, G0, G0, next); - } - - void stx_entry(Label &L, Register r1, Register r2, Register base, Register offs) - { - __ bind(L); - __ stx(r1, base, offs); - __ inc(offs, 8); - __ stx(r2, base, offs); - __ inc(offs, 8); - } - - void offs_entry(Label &Lbl0, Label &Lbl1) - { - assert(Lbl0.is_bound(), "must be"); - assert(Lbl1.is_bound(), "must be"); - - int offset = Lbl0.loc_pos() - Lbl1.loc_pos(); - - __ emit_data(offset); - } - - /* Generate the actual multiplication kernels for BigInteger vectors: - * - * 1. gen_mult_mpmul(...) - * - * 2. gen_mult_64x64(...) - * - * 3. gen_mult_64x64_unaligned(...) - * - * 4. gen_mult_32x32(...) - */ - void gen_mult_mpmul(Register len, Register xptr, Register yptr, Register zptr, - Label &L_exit) - { - const Register zero = G0; - const Register gxp = G1; // Need to use global registers across RWs. - const Register gyp = G2; - const Register gzp = G3; - const Register disp = G4; - const Register offs = G5; - - __ mov(xptr, gxp); - __ mov(yptr, gyp); - __ mov(zptr, gzp); - - /* Compute jump vector entry: - * - * 1. mpmul input size (0..31) x 64b - * 2. vector input size in 32b limbs (even number) - * 3. branch entries in reverse order (31..0), using two - * instructions per entry (2 * 4 bytes). - * - * displacement = byte_offset(bra_offset(len)) - * = byte_offset((64 - len)/2) - * = 8 * (64 - len)/2 - * = 4 * (64 - len) - */ - Register temp = I5; // Alright to use input regs. in first batch. - - __ sub(zero, len, temp); - __ add(temp, 64, temp); - __ sllx(temp, 2, disp); // disp := (64 - len) << 2 - - // Dispatch relative current PC, into instruction table below. - __ rdpc(temp); - __ add(temp, 16, temp); - __ jmp(temp, disp); - __ delayed()->clr(offs); - - ldd_entry(gxp, offs, F22); - ldd_entry(gxp, offs, F20); - ldd_entry(gxp, offs, F18); - ldd_entry(gxp, offs, F16); - ldd_entry(gxp, offs, F14); - ldd_entry(gxp, offs, F12); - ldd_entry(gxp, offs, F10); - ldd_entry(gxp, offs, F8); - ldd_entry(gxp, offs, F6); - ldd_entry(gxp, offs, F4); - ldx_entry(gxp, offs, I5); - ldx_entry(gxp, offs, I4); - ldx_entry(gxp, offs, I3); - ldx_entry(gxp, offs, I2); - ldx_entry(gxp, offs, I1); - ldx_entry(gxp, offs, I0); - ldx_entry(gxp, offs, L7); - ldx_entry(gxp, offs, L6); - ldx_entry(gxp, offs, L5); - ldx_entry(gxp, offs, L4); - ldx_entry(gxp, offs, L3); - ldx_entry(gxp, offs, L2); - ldx_entry(gxp, offs, L1); - ldx_entry(gxp, offs, L0); - ldd_entry(gxp, offs, F2); - ldd_entry(gxp, offs, F0); - ldx_entry(gxp, offs, O5); - ldx_entry(gxp, offs, O4); - ldx_entry(gxp, offs, O3); - ldx_entry(gxp, offs, O2); - ldx_entry(gxp, offs, O1); - ldx_entry(gxp, offs, O0); - - __ save(SP, -176, SP); - - const Register addr = gxp; // Alright to reuse 'gxp'. - - // Dispatch relative current PC, into instruction table below. - __ rdpc(addr); - __ add(addr, 16, addr); - __ jmp(addr, disp); - __ delayed()->clr(offs); - - ldd_entry(gyp, offs, F58); - ldd_entry(gyp, offs, F56); - ldd_entry(gyp, offs, F54); - ldd_entry(gyp, offs, F52); - ldd_entry(gyp, offs, F50); - ldd_entry(gyp, offs, F48); - ldd_entry(gyp, offs, F46); - ldd_entry(gyp, offs, F44); - ldd_entry(gyp, offs, F42); - ldd_entry(gyp, offs, F40); - ldd_entry(gyp, offs, F38); - ldd_entry(gyp, offs, F36); - ldd_entry(gyp, offs, F34); - ldd_entry(gyp, offs, F32); - ldd_entry(gyp, offs, F30); - ldd_entry(gyp, offs, F28); - ldd_entry(gyp, offs, F26); - ldd_entry(gyp, offs, F24); - ldx_entry(gyp, offs, O5); - ldx_entry(gyp, offs, O4); - ldx_entry(gyp, offs, O3); - ldx_entry(gyp, offs, O2); - ldx_entry(gyp, offs, O1); - ldx_entry(gyp, offs, O0); - ldx_entry(gyp, offs, L7); - ldx_entry(gyp, offs, L6); - ldx_entry(gyp, offs, L5); - ldx_entry(gyp, offs, L4); - ldx_entry(gyp, offs, L3); - ldx_entry(gyp, offs, L2); - ldx_entry(gyp, offs, L1); - ldx_entry(gyp, offs, L0); - - __ save(SP, -176, SP); - __ save(SP, -176, SP); - __ save(SP, -176, SP); - __ save(SP, -176, SP); - __ save(SP, -176, SP); - - Label L_mpmul_restore_4, L_mpmul_restore_3, L_mpmul_restore_2; - Label L_mpmul_restore_1, L_mpmul_restore_0; - - // Dispatch relative current PC, into instruction table below. - __ rdpc(addr); - __ add(addr, 16, addr); - __ jmp(addr, disp); - __ delayed()->clr(offs); - - mpmul_entry(31, L_mpmul_restore_0); - mpmul_entry(30, L_mpmul_restore_0); - mpmul_entry(29, L_mpmul_restore_0); - mpmul_entry(28, L_mpmul_restore_0); - mpmul_entry(27, L_mpmul_restore_1); - mpmul_entry(26, L_mpmul_restore_1); - mpmul_entry(25, L_mpmul_restore_1); - mpmul_entry(24, L_mpmul_restore_1); - mpmul_entry(23, L_mpmul_restore_1); - mpmul_entry(22, L_mpmul_restore_1); - mpmul_entry(21, L_mpmul_restore_1); - mpmul_entry(20, L_mpmul_restore_2); - mpmul_entry(19, L_mpmul_restore_2); - mpmul_entry(18, L_mpmul_restore_2); - mpmul_entry(17, L_mpmul_restore_2); - mpmul_entry(16, L_mpmul_restore_2); - mpmul_entry(15, L_mpmul_restore_2); - mpmul_entry(14, L_mpmul_restore_2); - mpmul_entry(13, L_mpmul_restore_3); - mpmul_entry(12, L_mpmul_restore_3); - mpmul_entry(11, L_mpmul_restore_3); - mpmul_entry(10, L_mpmul_restore_3); - mpmul_entry( 9, L_mpmul_restore_3); - mpmul_entry( 8, L_mpmul_restore_3); - mpmul_entry( 7, L_mpmul_restore_3); - mpmul_entry( 6, L_mpmul_restore_4); - mpmul_entry( 5, L_mpmul_restore_4); - mpmul_entry( 4, L_mpmul_restore_4); - mpmul_entry( 3, L_mpmul_restore_4); - mpmul_entry( 2, L_mpmul_restore_4); - mpmul_entry( 1, L_mpmul_restore_4); - mpmul_entry( 0, L_mpmul_restore_4); - - Label L_z31, L_z30, L_z29, L_z28, L_z27, L_z26, L_z25, L_z24; - Label L_z23, L_z22, L_z21, L_z20, L_z19, L_z18, L_z17, L_z16; - Label L_z15, L_z14, L_z13, L_z12, L_z11, L_z10, L_z09, L_z08; - Label L_z07, L_z06, L_z05, L_z04, L_z03, L_z02, L_z01, L_z00; - - Label L_zst_base; // Store sequence base address. - __ bind(L_zst_base); - - stx_entry(L_z31, L7, L6, gzp, offs); - stx_entry(L_z30, L5, L4, gzp, offs); - stx_entry(L_z29, L3, L2, gzp, offs); - stx_entry(L_z28, L1, L0, gzp, offs); - __ restore(); - stx_entry(L_z27, O5, O4, gzp, offs); - stx_entry(L_z26, O3, O2, gzp, offs); - stx_entry(L_z25, O1, O0, gzp, offs); - stx_entry(L_z24, L7, L6, gzp, offs); - stx_entry(L_z23, L5, L4, gzp, offs); - stx_entry(L_z22, L3, L2, gzp, offs); - stx_entry(L_z21, L1, L0, gzp, offs); - __ restore(); - stx_entry(L_z20, O5, O4, gzp, offs); - stx_entry(L_z19, O3, O2, gzp, offs); - stx_entry(L_z18, O1, O0, gzp, offs); - stx_entry(L_z17, L7, L6, gzp, offs); - stx_entry(L_z16, L5, L4, gzp, offs); - stx_entry(L_z15, L3, L2, gzp, offs); - stx_entry(L_z14, L1, L0, gzp, offs); - __ restore(); - stx_entry(L_z13, O5, O4, gzp, offs); - stx_entry(L_z12, O3, O2, gzp, offs); - stx_entry(L_z11, O1, O0, gzp, offs); - stx_entry(L_z10, L7, L6, gzp, offs); - stx_entry(L_z09, L5, L4, gzp, offs); - stx_entry(L_z08, L3, L2, gzp, offs); - stx_entry(L_z07, L1, L0, gzp, offs); - __ restore(); - stx_entry(L_z06, O5, O4, gzp, offs); - stx_entry(L_z05, O3, O2, gzp, offs); - stx_entry(L_z04, O1, O0, gzp, offs); - stx_entry(L_z03, L7, L6, gzp, offs); - stx_entry(L_z02, L5, L4, gzp, offs); - stx_entry(L_z01, L3, L2, gzp, offs); - stx_entry(L_z00, L1, L0, gzp, offs); - - __ restore(); - __ restore(); - // Exit out of 'mpmul' routine, back to multiplyToLen. - __ ba_short(L_exit); - - Label L_zst_offs; - __ bind(L_zst_offs); - - offs_entry(L_z31, L_zst_base); // index 31: 2048x2048 - offs_entry(L_z30, L_zst_base); - offs_entry(L_z29, L_zst_base); - offs_entry(L_z28, L_zst_base); - offs_entry(L_z27, L_zst_base); - offs_entry(L_z26, L_zst_base); - offs_entry(L_z25, L_zst_base); - offs_entry(L_z24, L_zst_base); - offs_entry(L_z23, L_zst_base); - offs_entry(L_z22, L_zst_base); - offs_entry(L_z21, L_zst_base); - offs_entry(L_z20, L_zst_base); - offs_entry(L_z19, L_zst_base); - offs_entry(L_z18, L_zst_base); - offs_entry(L_z17, L_zst_base); - offs_entry(L_z16, L_zst_base); - offs_entry(L_z15, L_zst_base); - offs_entry(L_z14, L_zst_base); - offs_entry(L_z13, L_zst_base); - offs_entry(L_z12, L_zst_base); - offs_entry(L_z11, L_zst_base); - offs_entry(L_z10, L_zst_base); - offs_entry(L_z09, L_zst_base); - offs_entry(L_z08, L_zst_base); - offs_entry(L_z07, L_zst_base); - offs_entry(L_z06, L_zst_base); - offs_entry(L_z05, L_zst_base); - offs_entry(L_z04, L_zst_base); - offs_entry(L_z03, L_zst_base); - offs_entry(L_z02, L_zst_base); - offs_entry(L_z01, L_zst_base); - offs_entry(L_z00, L_zst_base); // index 0: 64x64 - - __ bind(L_mpmul_restore_4); - __ restore(); - __ bind(L_mpmul_restore_3); - __ restore(); - __ bind(L_mpmul_restore_2); - __ restore(); - __ bind(L_mpmul_restore_1); - __ restore(); - __ bind(L_mpmul_restore_0); - - // Dispatch via offset vector entry, into z-store sequence. - Label L_zst_rdpc; - __ bind(L_zst_rdpc); - - assert(L_zst_base.is_bound(), "must be"); - assert(L_zst_offs.is_bound(), "must be"); - assert(L_zst_rdpc.is_bound(), "must be"); - - int dbase = L_zst_rdpc.loc_pos() - L_zst_base.loc_pos(); - int doffs = L_zst_rdpc.loc_pos() - L_zst_offs.loc_pos(); - - temp = gyp; // Alright to reuse 'gyp'. - - __ rdpc(addr); - __ sub(addr, doffs, temp); - __ srlx(disp, 1, disp); - __ lduw(temp, disp, offs); - __ sub(addr, dbase, temp); - __ jmp(temp, offs); - __ delayed()->clr(offs); - } - - void gen_mult_64x64(Register xp, Register xn, - Register yp, Register yn, - Register zp, Register zn, Label &L_exit) - { - // Assuming that a stack frame has already been created, i.e. local and - // output registers are available for immediate use. - - const Register ri = L0; // Outer loop index, xv[i] - const Register rj = L1; // Inner loop index, yv[j] - const Register rk = L2; // Output loop index, zv[k] - const Register rx = L4; // x-vector datum [i] - const Register ry = L5; // y-vector datum [j] - const Register rz = L6; // z-vector datum [k] - const Register rc = L7; // carry over (to z-vector datum [k-1]) - - const Register lop = O0; // lo-64b product - const Register hip = O1; // hi-64b product - - const Register zero = G0; - - Label L_loop_i, L_exit_loop_i; - Label L_loop_j; - Label L_loop_i2, L_exit_loop_i2; - - __ srlx(xn, 1, xn); // index for u32 to u64 ditto - __ srlx(yn, 1, yn); // index for u32 to u64 ditto - __ srlx(zn, 1, zn); // index for u32 to u64 ditto - __ dec(xn); // Adjust [0..(N/2)-1] - __ dec(yn); - __ dec(zn); - __ clr(rc); // u64 c = 0 - __ sllx(xn, 3, ri); // int i = xn (byte offset i = 8*xn) - __ sllx(yn, 3, rj); // int j = yn (byte offset i = 8*xn) - __ sllx(zn, 3, rk); // int k = zn (byte offset k = 8*zn) - __ ldx(yp, rj, ry); // u64 y = yp[yn] - - // for (int i = xn; i >= 0; i--) - __ bind(L_loop_i); - - __ cmp_and_br_short(ri, 0, // i >= 0 - Assembler::less, Assembler::pn, L_exit_loop_i); - __ ldx(xp, ri, rx); // x = xp[i] - __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 - __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 - __ addcc(rc, lop, lop); // Accumulate lower order bits (producing carry) - __ addxc(hip, zero, rc); // carry over to next datum [k-1] - __ stx(lop, zp, rk); // z[k] = lop - __ dec(rk, 8); // k-- - __ dec(ri, 8); // i-- - __ ba_short(L_loop_i); - - __ bind(L_exit_loop_i); - __ stx(rc, zp, rk); // z[k] = c - - // for (int j = yn - 1; j >= 0; j--) - __ sllx(yn, 3, rj); // int j = yn - 1 (byte offset j = 8*yn) - __ dec(rj, 8); - - __ bind(L_loop_j); - - __ cmp_and_br_short(rj, 0, // j >= 0 - Assembler::less, Assembler::pn, L_exit); - __ clr(rc); // u64 c = 0 - __ ldx(yp, rj, ry); // u64 y = yp[j] - - // for (int i = xn, k = --zn; i >= 0; i--) - __ dec(zn); // --zn - __ sllx(xn, 3, ri); // int i = xn (byte offset i = 8*xn) - __ sllx(zn, 3, rk); // int k = zn (byte offset k = 8*zn) - - __ bind(L_loop_i2); - - __ cmp_and_br_short(ri, 0, // i >= 0 - Assembler::less, Assembler::pn, L_exit_loop_i2); - __ ldx(xp, ri, rx); // x = xp[i] - __ ldx(zp, rk, rz); // z = zp[k], accumulator - __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 - __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 - __ addcc(rz, rc, rz); // Accumulate lower order bits, - __ addxc(hip, zero, rc); // Accumulate higher order bits to carry - __ addcc(rz, lop, rz); // z += lo(p) + c - __ addxc(rc, zero, rc); - __ stx(rz, zp, rk); // zp[k] = z - __ dec(rk, 8); // k-- - __ dec(ri, 8); // i-- - __ ba_short(L_loop_i2); - - __ bind(L_exit_loop_i2); - __ stx(rc, zp, rk); // z[k] = c - __ dec(rj, 8); // j-- - __ ba_short(L_loop_j); - } - - void gen_mult_64x64_unaligned(Register xp, Register xn, - Register yp, Register yn, - Register zp, Register zn, Label &L_exit) - { - // Assuming that a stack frame has already been created, i.e. local and - // output registers are available for use. - - const Register xpc = L0; // Outer loop cursor, xp[i] - const Register ypc = L1; // Inner loop cursor, yp[j] - const Register zpc = L2; // Output loop cursor, zp[k] - const Register rx = L4; // x-vector datum [i] - const Register ry = L5; // y-vector datum [j] - const Register rz = L6; // z-vector datum [k] - const Register rc = L7; // carry over (to z-vector datum [k-1]) - const Register rt = O2; - - const Register lop = O0; // lo-64b product - const Register hip = O1; // hi-64b product - - const Register zero = G0; - - Label L_loop_i, L_exit_loop_i; - Label L_loop_j; - Label L_loop_i2, L_exit_loop_i2; - - __ srlx(xn, 1, xn); // index for u32 to u64 ditto - __ srlx(yn, 1, yn); // index for u32 to u64 ditto - __ srlx(zn, 1, zn); // index for u32 to u64 ditto - __ dec(xn); // Adjust [0..(N/2)-1] - __ dec(yn); - __ dec(zn); - __ clr(rc); // u64 c = 0 - __ sllx(xn, 3, xpc); // u32* xpc = &xp[xn] (byte offset 8*xn) - __ add(xp, xpc, xpc); - __ sllx(yn, 3, ypc); // u32* ypc = &yp[yn] (byte offset 8*yn) - __ add(yp, ypc, ypc); - __ sllx(zn, 3, zpc); // u32* zpc = &zp[zn] (byte offset 8*zn) - __ add(zp, zpc, zpc); - __ lduw(ypc, 0, rt); // u64 y = yp[yn] - __ lduw(ypc, 4, ry); // ... - __ sllx(rt, 32, rt); - __ or3(rt, ry, ry); - - // for (int i = xn; i >= 0; i--) - __ bind(L_loop_i); - - __ cmp_and_brx_short(xpc, xp,// i >= 0 - Assembler::lessUnsigned, Assembler::pn, L_exit_loop_i); - __ lduw(xpc, 0, rt); // u64 x = xp[i] - __ lduw(xpc, 4, rx); // ... - __ sllx(rt, 32, rt); - __ or3(rt, rx, rx); - __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 - __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 - __ addcc(rc, lop, lop); // Accumulate lower order bits (producing carry) - __ addxc(hip, zero, rc); // carry over to next datum [k-1] - __ srlx(lop, 32, rt); - __ stw(rt, zpc, 0); // z[k] = lop - __ stw(lop, zpc, 4); // ... - __ dec(zpc, 8); // k-- (zpc--) - __ dec(xpc, 8); // i-- (xpc--) - __ ba_short(L_loop_i); - - __ bind(L_exit_loop_i); - __ srlx(rc, 32, rt); - __ stw(rt, zpc, 0); // z[k] = c - __ stw(rc, zpc, 4); - - // for (int j = yn - 1; j >= 0; j--) - __ sllx(yn, 3, ypc); // u32* ypc = &yp[yn] (byte offset 8*yn) - __ add(yp, ypc, ypc); - __ dec(ypc, 8); // yn - 1 (ypc--) - - __ bind(L_loop_j); - - __ cmp_and_brx_short(ypc, yp,// j >= 0 - Assembler::lessUnsigned, Assembler::pn, L_exit); - __ clr(rc); // u64 c = 0 - __ lduw(ypc, 0, rt); // u64 y = yp[j] (= *ypc) - __ lduw(ypc, 4, ry); // ... - __ sllx(rt, 32, rt); - __ or3(rt, ry, ry); - - // for (int i = xn, k = --zn; i >= 0; i--) - __ sllx(xn, 3, xpc); // u32* xpc = &xp[xn] (byte offset 8*xn) - __ add(xp, xpc, xpc); - __ dec(zn); // --zn - __ sllx(zn, 3, zpc); // u32* zpc = &zp[zn] (byte offset 8*zn) - __ add(zp, zpc, zpc); - - __ bind(L_loop_i2); - - __ cmp_and_brx_short(xpc, xp,// i >= 0 - Assembler::lessUnsigned, Assembler::pn, L_exit_loop_i2); - __ lduw(xpc, 0, rt); // u64 x = xp[i] (= *xpc) - __ lduw(xpc, 4, rx); // ... - __ sllx(rt, 32, rt); - __ or3(rt, rx, rx); - - __ lduw(zpc, 0, rt); // u64 z = zp[k] (= *zpc) - __ lduw(zpc, 4, rz); // ... - __ sllx(rt, 32, rt); - __ or3(rt, rz, rz); - - __ mulx(rx, ry, lop); // lo-64b-part of result 64x64 - __ umulxhi(rx, ry, hip); // hi-64b-part of result 64x64 - __ addcc(rz, rc, rz); // Accumulate lower order bits... - __ addxc(hip, zero, rc); // Accumulate higher order bits to carry - __ addcc(rz, lop, rz); // ... z += lo(p) + c - __ addxccc(rc, zero, rc); - __ srlx(rz, 32, rt); - __ stw(rt, zpc, 0); // zp[k] = z (*zpc = z) - __ stw(rz, zpc, 4); - __ dec(zpc, 8); // k-- (zpc--) - __ dec(xpc, 8); // i-- (xpc--) - __ ba_short(L_loop_i2); - - __ bind(L_exit_loop_i2); - __ srlx(rc, 32, rt); - __ stw(rt, zpc, 0); // z[k] = c - __ stw(rc, zpc, 4); - __ dec(ypc, 8); // j-- (ypc--) - __ ba_short(L_loop_j); - } - - void gen_mult_32x32(Register xp, Register xn, - Register yp, Register yn, - Register zp, Register zn, Label &L_exit) - { - // Assuming that a stack frame has already been created, i.e. local and - // output registers are available for use. - - const Register ri = L0; // Outer loop index, xv[i] - const Register rj = L1; // Inner loop index, yv[j] - const Register rk = L2; // Output loop index, zv[k] - const Register rx = L4; // x-vector datum [i] - const Register ry = L5; // y-vector datum [j] - const Register rz = L6; // z-vector datum [k] - const Register rc = L7; // carry over (to z-vector datum [k-1]) - - const Register p64 = O0; // 64b product - const Register z65 = O1; // carry+64b accumulator - const Register c65 = O2; // carry at bit 65 - const Register c33 = O2; // carry at bit 33 (after shift) - - const Register zero = G0; - - Label L_loop_i, L_exit_loop_i; - Label L_loop_j; - Label L_loop_i2, L_exit_loop_i2; - - __ dec(xn); // Adjust [0..N-1] - __ dec(yn); - __ dec(zn); - __ clr(rc); // u32 c = 0 - __ sllx(xn, 2, ri); // int i = xn (byte offset i = 4*xn) - __ sllx(yn, 2, rj); // int j = yn (byte offset i = 4*xn) - __ sllx(zn, 2, rk); // int k = zn (byte offset k = 4*zn) - __ lduw(yp, rj, ry); // u32 y = yp[yn] - - // for (int i = xn; i >= 0; i--) - __ bind(L_loop_i); - - __ cmp_and_br_short(ri, 0, // i >= 0 - Assembler::less, Assembler::pn, L_exit_loop_i); - __ lduw(xp, ri, rx); // x = xp[i] - __ mulx(rx, ry, p64); // 64b result of 32x32 - __ addcc(rc, p64, z65); // Accumulate to 65 bits (producing carry) - __ addxc(zero, zero, c65); // Materialise carry (in bit 65) into lsb, - __ sllx(c65, 32, c33); // and shift into bit 33 - __ srlx(z65, 32, rc); // carry = c33 | hi(z65) >> 32 - __ add(c33, rc, rc); // carry over to next datum [k-1] - __ stw(z65, zp, rk); // z[k] = lo(z65) - __ dec(rk, 4); // k-- - __ dec(ri, 4); // i-- - __ ba_short(L_loop_i); - - __ bind(L_exit_loop_i); - __ stw(rc, zp, rk); // z[k] = c - - // for (int j = yn - 1; j >= 0; j--) - __ sllx(yn, 2, rj); // int j = yn - 1 (byte offset j = 4*yn) - __ dec(rj, 4); - - __ bind(L_loop_j); - - __ cmp_and_br_short(rj, 0, // j >= 0 - Assembler::less, Assembler::pn, L_exit); - __ clr(rc); // u32 c = 0 - __ lduw(yp, rj, ry); // u32 y = yp[j] - - // for (int i = xn, k = --zn; i >= 0; i--) - __ dec(zn); // --zn - __ sllx(xn, 2, ri); // int i = xn (byte offset i = 4*xn) - __ sllx(zn, 2, rk); // int k = zn (byte offset k = 4*zn) - - __ bind(L_loop_i2); - - __ cmp_and_br_short(ri, 0, // i >= 0 - Assembler::less, Assembler::pn, L_exit_loop_i2); - __ lduw(xp, ri, rx); // x = xp[i] - __ lduw(zp, rk, rz); // z = zp[k], accumulator - __ mulx(rx, ry, p64); // 64b result of 32x32 - __ add(rz, rc, rz); // Accumulate lower order bits, - __ addcc(rz, p64, z65); // z += lo(p64) + c - __ addxc(zero, zero, c65); // Materialise carry (in bit 65) into lsb, - __ sllx(c65, 32, c33); // and shift into bit 33 - __ srlx(z65, 32, rc); // carry = c33 | hi(z65) >> 32 - __ add(c33, rc, rc); // carry over to next datum [k-1] - __ stw(z65, zp, rk); // zp[k] = lo(z65) - __ dec(rk, 4); // k-- - __ dec(ri, 4); // i-- - __ ba_short(L_loop_i2); - - __ bind(L_exit_loop_i2); - __ stw(rc, zp, rk); // z[k] = c - __ dec(rj, 4); // j-- - __ ba_short(L_loop_j); - } - - - void generate_initial() { - // Generates all stubs and initializes the entry points - - //------------------------------------------------------------------------------------------------------------------------ - // entry points that exist in all platforms - // Note: This is code that could be shared among different platforms - however the benefit seems to be smaller than - // the disadvantage of having a much more complicated generator structure. See also comment in stubRoutines.hpp. - StubRoutines::_forward_exception_entry = generate_forward_exception(); - - StubRoutines::_call_stub_entry = generate_call_stub(StubRoutines::_call_stub_return_address); - StubRoutines::_catch_exception_entry = generate_catch_exception(); - - //------------------------------------------------------------------------------------------------------------------------ - // entry points that are platform specific - StubRoutines::Sparc::_test_stop_entry = generate_test_stop(); - - StubRoutines::Sparc::_stop_subroutine_entry = generate_stop_subroutine(); - StubRoutines::Sparc::_flush_callers_register_windows_entry = generate_flush_callers_register_windows(); - - // Build this early so it's available for the interpreter. - StubRoutines::_throw_StackOverflowError_entry = - generate_throw_exception("StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError)); - StubRoutines::_throw_delayed_StackOverflowError_entry = - generate_throw_exception("delayed StackOverflowError throw_exception", - CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError)); - - if (UseCRC32Intrinsics) { - // set table address before stub generation which use it - StubRoutines::_crc_table_adr = (address)StubRoutines::Sparc::_crc_table; - StubRoutines::_updateBytesCRC32 = generate_updateBytesCRC32(); - } - - if (UseCRC32CIntrinsics) { - // set table address before stub generation which use it - StubRoutines::_crc32c_table_addr = (address)StubRoutines::Sparc::_crc32c_table; - StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C(); - } - } - - - void generate_all() { - // Generates all stubs and initializes the entry points - - // Generate partial_subtype_check first here since its code depends on - // UseZeroBaseCompressedOops which is defined after heap initialization. - StubRoutines::Sparc::_partial_subtype_check = generate_partial_subtype_check(); - // These entry points require SharedInfo::stack0 to be set up in non-core builds - StubRoutines::_throw_AbstractMethodError_entry = generate_throw_exception("AbstractMethodError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_AbstractMethodError)); - StubRoutines::_throw_IncompatibleClassChangeError_entry= generate_throw_exception("IncompatibleClassChangeError throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_IncompatibleClassChangeError)); - StubRoutines::_throw_NullPointerException_at_call_entry= generate_throw_exception("NullPointerException at call throw_exception", CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call)); - - // support for verify_oop (must happen after universe_init) - StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop_subroutine(); - - // arraycopy stubs used by compilers - generate_arraycopy_stubs(); - - // Don't initialize the platform math functions since sparc - // doesn't have intrinsics for these operations. - - // Safefetch stubs. - generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, - &StubRoutines::_safefetch32_fault_pc, - &StubRoutines::_safefetch32_continuation_pc); - generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry, - &StubRoutines::_safefetchN_fault_pc, - &StubRoutines::_safefetchN_continuation_pc); - - // generate AES intrinsics code - if (UseAESIntrinsics) { - StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); - StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); - StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); - StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); - } - // generate GHASH intrinsics code - if (UseGHASHIntrinsics) { - StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); - } - - // generate SHA1/SHA256/SHA512 intrinsics code - if (UseSHA1Intrinsics) { - StubRoutines::_sha1_implCompress = generate_sha1_implCompress(false, "sha1_implCompress"); - StubRoutines::_sha1_implCompressMB = generate_sha1_implCompress(true, "sha1_implCompressMB"); - } - if (UseSHA256Intrinsics) { - StubRoutines::_sha256_implCompress = generate_sha256_implCompress(false, "sha256_implCompress"); - StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB"); - } - if (UseSHA512Intrinsics) { - StubRoutines::_sha512_implCompress = generate_sha512_implCompress(false, "sha512_implCompress"); - StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(true, "sha512_implCompressMB"); - } - // generate Adler32 intrinsics code - if (UseAdler32Intrinsics) { - StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); - } - -#ifdef COMPILER2 - // Intrinsics supported by C2 only: - if (UseMultiplyToLenIntrinsic) { - StubRoutines::_multiplyToLen = generate_multiplyToLen(); - } -#endif // COMPILER2 - } - - public: - StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { - // replace the standard masm with a special one: - _masm = new MacroAssembler(code); - - _stub_count = !all ? 0x100 : 0x200; - if (all) { - generate_all(); - } else { - generate_initial(); - } - - // make sure this stub is available for all local calls - if (_atomic_add_stub.is_unbound()) { - // generate a second time, if necessary - (void) generate_atomic_add(); - } - } - - - private: - int _stub_count; - void stub_prolog(StubCodeDesc* cdesc) { - # ifdef ASSERT - // put extra information in the stub code, to make it more readable - // Write the high part of the address - // [RGV] Check if there is a dependency on the size of this prolog - __ emit_data((intptr_t)cdesc >> 32, relocInfo::none); - __ emit_data((intptr_t)cdesc, relocInfo::none); - __ emit_data(++_stub_count, relocInfo::none); - # endif - align(true); - } - - void align(bool at_header = false) { - // %%%%% move this constant somewhere else - // UltraSPARC cache line size is 8 instructions: - const unsigned int icache_line_size = 32; - const unsigned int icache_half_line_size = 16; - - if (at_header) { - while ((intptr_t)(__ pc()) % icache_line_size != 0) { - __ emit_data(0, relocInfo::none); - } - } else { - while ((intptr_t)(__ pc()) % icache_half_line_size != 0) { - __ nop(); - } - } - } - -}; // end class declaration - -#define UCM_TABLE_MAX_ENTRIES 8 -void StubGenerator_generate(CodeBuffer* code, bool all) { - if (UnsafeCopyMemory::_table == NULL) { - UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES); - } - StubGenerator g(code, all); -} diff --git a/src/hotspot/cpu/sparc/stubRoutines_sparc.cpp b/src/hotspot/cpu/sparc/stubRoutines_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/stubRoutines_sparc.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 1997, 2016, 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. - * - */ - -#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. - - -extern "C" { - address _flush_reg_windows(); // in .s file. - // Flush registers to stack. In case of error we will need to stack walk. - address bootstrap_flush_windows(void) { - Thread* thread = Thread::current_or_null(); - // Very early in process there is no thread. - if (thread != NULL) { - guarantee(thread->is_Java_thread(), "Not a Java thread."); - JavaThread* jt = (JavaThread*)thread; - guarantee(!jt->has_last_Java_frame(), "Must be able to flush registers!"); - } - return (address)_flush_reg_windows(); - }; -}; - -address StubRoutines::Sparc::_test_stop_entry = NULL; -address StubRoutines::Sparc::_stop_subroutine_entry = NULL; -address StubRoutines::Sparc::_flush_callers_register_windows_entry = CAST_FROM_FN_PTR(address, bootstrap_flush_windows); - -address StubRoutines::Sparc::_partial_subtype_check = NULL; - -uint64_t StubRoutines::Sparc::_crc_by128_masks[] = -{ - /* The fields in this structure are arranged so that they can be - * picked up two at a time with 128-bit loads. - * - * Because of flipped bit order for this CRC polynomials - * the constant for X**N is left-shifted by 1. This is because - * a 64 x 64 polynomial multiply produces a 127-bit result - * but the highest term is always aligned to bit 0 in the container. - * Pre-shifting by one fixes this, at the cost of potentially making - * the 32-bit constant no longer fit in a 32-bit container (thus the - * use of uint64_t, though this is also the size used by the carry- - * less multiply instruction. - * - * In addition, the flipped bit order and highest-term-at-least-bit - * multiply changes the constants used. The 96-bit result will be - * aligned to the high-term end of the target 128-bit container, - * not the low-term end; that is, instead of a 512-bit or 576-bit fold, - * instead it is a 480 (=512-32) or 544 (=512+64-32) bit fold. - * - * This cause additional problems in the 128-to-64-bit reduction; see the - * code for details. By storing a mask in the otherwise unused half of - * a 128-bit constant, bits can be cleared before multiplication without - * storing and reloading. Note that staying on a 128-bit datapath means - * that some data is uselessly stored and some unused data is intersected - * with an irrelevant constant. - */ - - ((uint64_t) 0xffffffffUL), /* low of K_M_64 */ - ((uint64_t) 0xb1e6b092U << 1), /* high of K_M_64 */ - ((uint64_t) 0xba8ccbe8U << 1), /* low of K_160_96 */ - ((uint64_t) 0x6655004fU << 1), /* high of K_160_96 */ - ((uint64_t) 0xaa2215eaU << 1), /* low of K_544_480 */ - ((uint64_t) 0xe3720acbU << 1) /* high of K_544_480 */ -}; - -/** - * crc_table[] from jdk/src/java.base/share/native/libzip/zlib-1.2.8/crc32.h - */ -juint StubRoutines::Sparc::_crc_table[] = -{ - 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 -}; - -/** - * CRC32C constants lookup table - */ -juint StubRoutines::Sparc::_crc32c_table[] = -{ - 0x00000000UL, 0xF26B8303UL, 0xE13B70F7UL, 0x1350F3F4UL, 0xC79A971FUL, - 0x35F1141CUL, 0x26A1E7E8UL, 0xD4CA64EBUL, 0x8AD958CFUL, 0x78B2DBCCUL, - 0x6BE22838UL, 0x9989AB3BUL, 0x4D43CFD0UL, 0xBF284CD3UL, 0xAC78BF27UL, - 0x5E133C24UL, 0x105EC76FUL, 0xE235446CUL, 0xF165B798UL, 0x030E349BUL, - 0xD7C45070UL, 0x25AFD373UL, 0x36FF2087UL, 0xC494A384UL, 0x9A879FA0UL, - 0x68EC1CA3UL, 0x7BBCEF57UL, 0x89D76C54UL, 0x5D1D08BFUL, 0xAF768BBCUL, - 0xBC267848UL, 0x4E4DFB4BUL, 0x20BD8EDEUL, 0xD2D60DDDUL, 0xC186FE29UL, - 0x33ED7D2AUL, 0xE72719C1UL, 0x154C9AC2UL, 0x061C6936UL, 0xF477EA35UL, - 0xAA64D611UL, 0x580F5512UL, 0x4B5FA6E6UL, 0xB93425E5UL, 0x6DFE410EUL, - 0x9F95C20DUL, 0x8CC531F9UL, 0x7EAEB2FAUL, 0x30E349B1UL, 0xC288CAB2UL, - 0xD1D83946UL, 0x23B3BA45UL, 0xF779DEAEUL, 0x05125DADUL, 0x1642AE59UL, - 0xE4292D5AUL, 0xBA3A117EUL, 0x4851927DUL, 0x5B016189UL, 0xA96AE28AUL, - 0x7DA08661UL, 0x8FCB0562UL, 0x9C9BF696UL, 0x6EF07595UL, 0x417B1DBCUL, - 0xB3109EBFUL, 0xA0406D4BUL, 0x522BEE48UL, 0x86E18AA3UL, 0x748A09A0UL, - 0x67DAFA54UL, 0x95B17957UL, 0xCBA24573UL, 0x39C9C670UL, 0x2A993584UL, - 0xD8F2B687UL, 0x0C38D26CUL, 0xFE53516FUL, 0xED03A29BUL, 0x1F682198UL, - 0x5125DAD3UL, 0xA34E59D0UL, 0xB01EAA24UL, 0x42752927UL, 0x96BF4DCCUL, - 0x64D4CECFUL, 0x77843D3BUL, 0x85EFBE38UL, 0xDBFC821CUL, 0x2997011FUL, - 0x3AC7F2EBUL, 0xC8AC71E8UL, 0x1C661503UL, 0xEE0D9600UL, 0xFD5D65F4UL, - 0x0F36E6F7UL, 0x61C69362UL, 0x93AD1061UL, 0x80FDE395UL, 0x72966096UL, - 0xA65C047DUL, 0x5437877EUL, 0x4767748AUL, 0xB50CF789UL, 0xEB1FCBADUL, - 0x197448AEUL, 0x0A24BB5AUL, 0xF84F3859UL, 0x2C855CB2UL, 0xDEEEDFB1UL, - 0xCDBE2C45UL, 0x3FD5AF46UL, 0x7198540DUL, 0x83F3D70EUL, 0x90A324FAUL, - 0x62C8A7F9UL, 0xB602C312UL, 0x44694011UL, 0x5739B3E5UL, 0xA55230E6UL, - 0xFB410CC2UL, 0x092A8FC1UL, 0x1A7A7C35UL, 0xE811FF36UL, 0x3CDB9BDDUL, - 0xCEB018DEUL, 0xDDE0EB2AUL, 0x2F8B6829UL, 0x82F63B78UL, 0x709DB87BUL, - 0x63CD4B8FUL, 0x91A6C88CUL, 0x456CAC67UL, 0xB7072F64UL, 0xA457DC90UL, - 0x563C5F93UL, 0x082F63B7UL, 0xFA44E0B4UL, 0xE9141340UL, 0x1B7F9043UL, - 0xCFB5F4A8UL, 0x3DDE77ABUL, 0x2E8E845FUL, 0xDCE5075CUL, 0x92A8FC17UL, - 0x60C37F14UL, 0x73938CE0UL, 0x81F80FE3UL, 0x55326B08UL, 0xA759E80BUL, - 0xB4091BFFUL, 0x466298FCUL, 0x1871A4D8UL, 0xEA1A27DBUL, 0xF94AD42FUL, - 0x0B21572CUL, 0xDFEB33C7UL, 0x2D80B0C4UL, 0x3ED04330UL, 0xCCBBC033UL, - 0xA24BB5A6UL, 0x502036A5UL, 0x4370C551UL, 0xB11B4652UL, 0x65D122B9UL, - 0x97BAA1BAUL, 0x84EA524EUL, 0x7681D14DUL, 0x2892ED69UL, 0xDAF96E6AUL, - 0xC9A99D9EUL, 0x3BC21E9DUL, 0xEF087A76UL, 0x1D63F975UL, 0x0E330A81UL, - 0xFC588982UL, 0xB21572C9UL, 0x407EF1CAUL, 0x532E023EUL, 0xA145813DUL, - 0x758FE5D6UL, 0x87E466D5UL, 0x94B49521UL, 0x66DF1622UL, 0x38CC2A06UL, - 0xCAA7A905UL, 0xD9F75AF1UL, 0x2B9CD9F2UL, 0xFF56BD19UL, 0x0D3D3E1AUL, - 0x1E6DCDEEUL, 0xEC064EEDUL, 0xC38D26C4UL, 0x31E6A5C7UL, 0x22B65633UL, - 0xD0DDD530UL, 0x0417B1DBUL, 0xF67C32D8UL, 0xE52CC12CUL, 0x1747422FUL, - 0x49547E0BUL, 0xBB3FFD08UL, 0xA86F0EFCUL, 0x5A048DFFUL, 0x8ECEE914UL, - 0x7CA56A17UL, 0x6FF599E3UL, 0x9D9E1AE0UL, 0xD3D3E1ABUL, 0x21B862A8UL, - 0x32E8915CUL, 0xC083125FUL, 0x144976B4UL, 0xE622F5B7UL, 0xF5720643UL, - 0x07198540UL, 0x590AB964UL, 0xAB613A67UL, 0xB831C993UL, 0x4A5A4A90UL, - 0x9E902E7BUL, 0x6CFBAD78UL, 0x7FAB5E8CUL, 0x8DC0DD8FUL, 0xE330A81AUL, - 0x115B2B19UL, 0x020BD8EDUL, 0xF0605BEEUL, 0x24AA3F05UL, 0xD6C1BC06UL, - 0xC5914FF2UL, 0x37FACCF1UL, 0x69E9F0D5UL, 0x9B8273D6UL, 0x88D28022UL, - 0x7AB90321UL, 0xAE7367CAUL, 0x5C18E4C9UL, 0x4F48173DUL, 0xBD23943EUL, - 0xF36E6F75UL, 0x0105EC76UL, 0x12551F82UL, 0xE03E9C81UL, 0x34F4F86AUL, - 0xC69F7B69UL, 0xD5CF889DUL, 0x27A40B9EUL, 0x79B737BAUL, 0x8BDCB4B9UL, - 0x988C474DUL, 0x6AE7C44EUL, 0xBE2DA0A5UL, 0x4C4623A6UL, 0x5F16D052UL, - 0xAD7D5351UL -}; diff --git a/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp b/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/stubRoutines_sparc.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_STUBROUTINES_SPARC_HPP -#define CPU_SPARC_STUBROUTINES_SPARC_HPP - -// This file holds the platform specific parts of the StubRoutines -// definition. See stubRoutines.hpp for a description on how to -// extend it. - - -// So unfortunately c2 will call with a pc from a frame object -// (already adjusted) and a raw pc (unadjusted), so we need to check both. -// It didn't use to be like this before adapter removal. -static bool returns_to_call_stub(address return_pc) { - return ((return_pc + frame::pc_return_offset) == _call_stub_return_address) || - (return_pc == _call_stub_return_address ); -} - -enum /* platform_dependent_constants */ { - // %%%%%%%% May be able to shrink this a lot - code_size1 = 20000, // simply increase if too small (assembler will crash if too small) - code_size2 = 29000 // simply increase if too small (assembler will crash if too small) -}; - -class Sparc { - friend class StubGenerator; - - private: - static address _test_stop_entry; - static address _stop_subroutine_entry; - static address _flush_callers_register_windows_entry; - - static address _partial_subtype_check; - // masks and table for CRC32 - static uint64_t _crc_by128_masks[]; - static juint _crc_table[]; - static juint _crc32c_table[]; - - public: - // test assembler stop routine by setting registers - static void (*test_stop_entry()) () { return CAST_TO_FN_PTR(void (*)(void), _test_stop_entry); } - - // a subroutine for debugging assembler code - static address stop_subroutine_entry_address() { return (address)&_stop_subroutine_entry; } - - // flushes (all but current) register window - static intptr_t* (*flush_callers_register_windows_func())() { return CAST_TO_FN_PTR(intptr_t* (*)(void), _flush_callers_register_windows_entry); } - - static address partial_subtype_check() { return _partial_subtype_check; } - - static address crc_by128_masks_addr() { return (address)_crc_by128_masks; } -}; - -#endif // CPU_SPARC_STUBROUTINES_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp b/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp +++ /dev/null @@ -1,1965 +0,0 @@ -/* - * Copyright (c) 1997, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/barrierSetAssembler.hpp" -#include "interpreter/bytecodeHistogram.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" -#include "interpreter/templateInterpreterGenerator.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 "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/align.hpp" -#include "utilities/debug.hpp" -#include "utilities/macros.hpp" - -// 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 -// The sethi() instruction generates lots more instructions when shell -// stack limit is unlimited, so that's why this is much bigger. -int TemplateInterpreter::InterpreterCodeSize = 260 * K; - -// Generation of Interpreter -// -// The TemplateInterpreterGenerator generates the interpreter into Interpreter::_code. - - -#define __ _masm-> - - -//---------------------------------------------------------------------------------------------------- - -// LP64 passes floating point arguments in F1, F3, F5, etc. instead of -// O0, O1, O2 etc.. -// Doubles are passed in D0, D2, D4 -// We store the signature of the first 16 arguments in the first argument -// slot because it will be overwritten prior to calling the native -// function, with the pointer to the JNIEnv. -// If LP64 there can be up to 16 floating point arguments in registers -// or 6 integer registers. -address TemplateInterpreterGenerator::generate_slow_signature_handler() { - - enum { - non_float = 0, - float_sig = 1, - double_sig = 2, - sig_mask = 3 - }; - - address entry = __ pc(); - Argument argv(0, true); - - // We are in the jni transition frame. Save the last_java_frame corresponding to the - // outer interpreter frame - // - __ set_last_Java_frame(FP, noreg); - // make sure the interpreter frame we've pushed has a valid return pc - __ mov(O7, I7); - __ mov(Lmethod, G3_scratch); - __ mov(Llocals, G4_scratch); - __ save_frame(0); - __ mov(G2_thread, L7_thread_cache); - __ add(argv.address_in_frame(), O3); - __ mov(G2_thread, O0); - __ mov(G3_scratch, O1); - __ call(CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), relocInfo::runtime_call_type); - __ delayed()->mov(G4_scratch, O2); - __ mov(L7_thread_cache, G2_thread); - __ reset_last_Java_frame(); - - - // load the register arguments (the C code packed them as varargs) - Address Sig = argv.address_in_frame(); // Argument 0 holds the signature - __ ld_ptr( Sig, G3_scratch ); // Get register argument signature word into G3_scratch - __ mov( G3_scratch, G4_scratch); - __ srl( G4_scratch, 2, G4_scratch); // Skip Arg 0 - Label done; - for (Argument ldarg = argv.successor(); ldarg.is_float_register(); ldarg = ldarg.successor()) { - Label NonFloatArg; - Label LoadFloatArg; - Label LoadDoubleArg; - Label NextArg; - Address a = ldarg.address_in_frame(); - __ andcc(G4_scratch, sig_mask, G3_scratch); - __ br(Assembler::zero, false, Assembler::pt, NonFloatArg); - __ delayed()->nop(); - - __ cmp(G3_scratch, float_sig ); - __ br(Assembler::equal, false, Assembler::pt, LoadFloatArg); - __ delayed()->nop(); - - __ cmp(G3_scratch, double_sig ); - __ br(Assembler::equal, false, Assembler::pt, LoadDoubleArg); - __ delayed()->nop(); - - __ bind(NonFloatArg); - // There are only 6 integer register arguments! - if ( ldarg.is_register() ) - __ ld_ptr(ldarg.address_in_frame(), ldarg.as_register()); - else { - // Optimization, see if there are any more args and get out prior to checking - // all 16 float registers. My guess is that this is rare. - // If is_register is false, then we are done the first six integer args. - __ br_null_short(G4_scratch, Assembler::pt, done); - } - __ ba(NextArg); - __ delayed()->srl( G4_scratch, 2, G4_scratch ); - - __ bind(LoadFloatArg); - __ ldf( FloatRegisterImpl::S, a, ldarg.as_float_register(), 4); - __ ba(NextArg); - __ delayed()->srl( G4_scratch, 2, G4_scratch ); - - __ bind(LoadDoubleArg); - __ ldf( FloatRegisterImpl::D, a, ldarg.as_double_register() ); - __ ba(NextArg); - __ delayed()->srl( G4_scratch, 2, G4_scratch ); - - __ bind(NextArg); - } - - __ bind(done); - __ ret(); - __ delayed()->restore(O0, 0, Lscratch); // caller's Lscratch gets the result handler - - return entry; -} - -void TemplateInterpreterGenerator::generate_counter_overflow(Label& Lcontinue) { - - // Generate code to initiate compilation on the counter overflow. - - // InterpreterRuntime::frequency_counter_overflow takes two arguments, - // the first indicates if the counter overflow occurs at a backwards branch (NULL bcp) - // and the second is only used when the first is true. We pass zero for both. - // The call returns the address of the verified entry point for the method or NULL - // if the compilation did not complete (either went background or bailed out). - __ set((int)false, O2); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), O2, O2, true); - // returns verified_entry_point or NULL - // we ignore it in any case - __ ba_short(Lcontinue); -} - - -// End of helpers - -// Various method entries - -// Abstract method entry -// Attempt to execute abstract method. Throw exception -// -address TemplateInterpreterGenerator::generate_abstract_entry(void) { - address entry = __ pc(); - // abstract method entry - // throw exception - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorWithMethod), G5_method); - // the call_VM checks for exception, so we should never return here. - __ should_not_reach_here(); - return entry; -} - -void TemplateInterpreterGenerator::save_native_result(void) { - // result potentially in O0/O1: save it across calls - const Address& l_tmp = InterpreterMacroAssembler::l_tmp; - - // result potentially in F0/F1: save it across calls - const Address& d_tmp = InterpreterMacroAssembler::d_tmp; - - // save and restore any potential method result value around the unlocking operation - __ stf(FloatRegisterImpl::D, F0, d_tmp); - __ stx(O0, l_tmp); -} - -void TemplateInterpreterGenerator::restore_native_result(void) { - const Address& l_tmp = InterpreterMacroAssembler::l_tmp; - const Address& d_tmp = InterpreterMacroAssembler::d_tmp; - - // Restore any method result value - __ ldf(FloatRegisterImpl::D, d_tmp, F0); - __ ldx(l_tmp, O0); -} - -address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) { - assert(!pass_oop || message == NULL, "either oop or message but not both"); - address entry = __ pc(); - // expression stack must be empty before entering the VM if an exception happened - __ empty_expression_stack(); - // load exception object - __ set((intptr_t)name, G3_scratch); - if (pass_oop) { - __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_klass_exception), G3_scratch, Otos_i); - } else { - __ set((intptr_t)message, G4_scratch); - __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), G3_scratch, G4_scratch); - } - // throw exception - assert(Interpreter::throw_exception_entry() != NULL, "generate it first"); - AddressLiteral thrower(Interpreter::throw_exception_entry()); - __ jump_to(thrower, G3_scratch); - __ delayed()->nop(); - return entry; -} - -address TemplateInterpreterGenerator::generate_ClassCastException_handler() { - address entry = __ pc(); - // expression stack must be empty before entering the VM if an exception - // happened - __ empty_expression_stack(); - // load exception object - __ call_VM(Oexception, - CAST_FROM_FN_PTR(address, - InterpreterRuntime::throw_ClassCastException), - Otos_i); - __ should_not_reach_here(); - return entry; -} - - -address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { - address entry = __ pc(); - // expression stack must be empty before entering the VM if an exception happened - __ empty_expression_stack(); - // Pass the array to create more detailed exceptions. - // convention: expect aberrant index in register G3_scratch, then shuffle the - // index to G4_scratch for the VM call - __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException), G3_scratch, Otos_i); - __ should_not_reach_here(); - return entry; -} - - -address TemplateInterpreterGenerator::generate_StackOverflowError_handler() { - address entry = __ pc(); - // expression stack must be empty before entering the VM if an exception happened - __ empty_expression_stack(); - __ call_VM(Oexception, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError)); - __ should_not_reach_here(); - return entry; -} - - -address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) { - address entry = __ pc(); - - if (state == atos) { - __ profile_return_type(O0, G3_scratch, G1_scratch); - } - - // The callee returns with the stack possibly adjusted by adapter transition - // We remove that possible adjustment here. - // All interpreter local registers are untouched. Any result is passed back - // in the O0/O1 or float registers. Before continuing, the arguments must be - // popped from the java expression stack; i.e., Lesp must be adjusted. - - __ mov(Llast_SP, SP); // Remove any adapter added stack space. - - const Register cache = G3_scratch; - const Register index = G1_scratch; - __ get_cache_and_index_at_bcp(cache, index, 1, index_size); - - const Register flags = cache; - __ ld_ptr(cache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset(), flags); - const Register parameter_size = flags; - __ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, parameter_size); // argument size in words - __ sll(parameter_size, Interpreter::logStackElementSize, parameter_size); // each argument size in bytes - __ add(Lesp, parameter_size, Lesp); // pop arguments - - __ check_and_handle_popframe(Gtemp); - __ check_and_handle_earlyret(Gtemp); - - __ dispatch_next(state, step); - - return entry; -} - - -address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, int step, address continuation) { - address entry = __ pc(); - __ get_constant_pool_cache(LcpoolCache); // load LcpoolCache -#if INCLUDE_JVMCI - // Check if we need to take lock at entry of synchronized method. This can - // only occur on method entry so emit it only for vtos with step 0. - if (EnableJVMCI && state == vtos && step == 0) { - Label L; - Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset()); - __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter - __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L); - // Clear flag. - __ stbool(G0, pending_monitor_enter_addr); - // Take lock. - lock_method(); - __ bind(L); - } else { -#ifdef ASSERT - if (EnableJVMCI) { - Label L; - Address pending_monitor_enter_addr(G2_thread, JavaThread::pending_monitorenter_offset()); - __ ldbool(pending_monitor_enter_addr, Gtemp); // Load if pending monitor enter - __ cmp_and_br_short(Gtemp, G0, Assembler::equal, Assembler::pn, L); - __ stop("unexpected pending monitor in deopt entry"); - __ bind(L); - } -#endif - } -#endif - { Label L; - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - __ ld_ptr(exception_addr, Gtemp); // Load pending exception. - __ br_null_short(Gtemp, Assembler::pt, L); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception)); - __ should_not_reach_here(); - __ bind(L); - } - if (continuation == NULL) { - __ dispatch_next(state, step); - } else { - __ jump_to_entry(continuation); - } - return entry; -} - -// A result handler converts/unboxes a native call result into -// a java interpreter/compiler result. The current frame is an -// interpreter frame. The activation frame unwind code must be -// consistent with that of TemplateTable::_return(...). In the -// case of native methods, the caller's SP was not modified. -address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) { - address entry = __ pc(); - Register Itos_i = Otos_i ->after_save(); - Register Itos_l = Otos_l ->after_save(); - Register Itos_l1 = Otos_l1->after_save(); - Register Itos_l2 = Otos_l2->after_save(); - switch (type) { - case T_BOOLEAN: __ subcc(G0, O0, G0); __ addc(G0, 0, Itos_i); break; // !0 => true; 0 => false - case T_CHAR : __ sll(O0, 16, O0); __ srl(O0, 16, Itos_i); break; // cannot use and3, 0xFFFF too big as immediate value! - case T_BYTE : __ sll(O0, 24, O0); __ sra(O0, 24, Itos_i); break; - case T_SHORT : __ sll(O0, 16, O0); __ sra(O0, 16, Itos_i); break; - case T_LONG : - case T_INT : __ mov(O0, Itos_i); break; - case T_VOID : /* nothing to do */ break; - case T_FLOAT : assert(F0 == Ftos_f, "fix this code" ); break; - case T_DOUBLE : assert(F0 == Ftos_d, "fix this code" ); break; - case T_OBJECT : - __ ld_ptr(FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS, Itos_i); - __ verify_oop(Itos_i); - break; - default : ShouldNotReachHere(); - } - __ ret(); // return from interpreter activation - __ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame - NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly - return entry; -} - -address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, address runtime_entry) { - address entry = __ pc(); - __ push(state); - __ call_VM(noreg, runtime_entry); - __ dispatch_via(vtos, Interpreter::normal_table(vtos)); - return entry; -} - - -// -// Helpers for commoning out cases in the various type of method entries. -// - -// increment invocation count & check for overflow -// -// Note: checking for negative value instead of overflow -// so we have a 'sticky' overflow test -// -// Lmethod: method -// ??: invocation counter -// -void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) { - // Note: In tiered we increment either counters in MethodCounters* or in - // MDO depending if we're profiling or not. - const Register G3_method_counters = G3_scratch; - Label done; - - if (TieredCompilation) { - const int increment = InvocationCounter::count_increment; - Label no_mdo; - if (ProfileInterpreter) { - // If no method data exists, go to profile_continue. - __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); - __ br_null_short(G4_scratch, Assembler::pn, no_mdo); - // Increment counter - Address mdo_invocation_counter(G4_scratch, - in_bytes(MethodData::invocation_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); - Address mask(G4_scratch, in_bytes(MethodData::invoke_mask_offset())); - __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, - G3_scratch, Lscratch, - Assembler::zero, overflow); - __ ba_short(done); - } - - // Increment counter in MethodCounters* - __ bind(no_mdo); - Address invocation_counter(G3_method_counters, - in_bytes(MethodCounters::invocation_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); - __ get_method_counters(Lmethod, G3_method_counters, done); - Address mask(G3_method_counters, in_bytes(MethodCounters::invoke_mask_offset())); - __ increment_mask_and_jump(invocation_counter, increment, mask, - G4_scratch, Lscratch, - Assembler::zero, overflow); - __ bind(done); - } else { // not TieredCompilation - // Update standard invocation counters - __ get_method_counters(Lmethod, G3_method_counters, done); - __ increment_invocation_counter(G3_method_counters, O0, G4_scratch); - if (ProfileInterpreter) { - Address interpreter_invocation_counter(G3_method_counters, - in_bytes(MethodCounters::interpreter_invocation_counter_offset())); - __ ld(interpreter_invocation_counter, G4_scratch); - __ inc(G4_scratch); - __ st(G4_scratch, interpreter_invocation_counter); - } - - if (ProfileInterpreter && profile_method != NULL) { - // Test to see if we should create a method data oop - Address profile_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_profile_limit_offset())); - __ ld(profile_limit, G1_scratch); - __ cmp_and_br_short(O0, G1_scratch, Assembler::lessUnsigned, Assembler::pn, *profile_method_continue); - - // if no method data exists, go to profile_method - __ test_method_data_pointer(*profile_method); - } - - Address invocation_limit(G3_method_counters, in_bytes(MethodCounters::interpreter_invocation_limit_offset())); - __ ld(invocation_limit, G3_scratch); - __ cmp(O0, G3_scratch); - __ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow); // Far distance - __ delayed()->nop(); - __ bind(done); - } -} - -// Allocate monitor and lock method (asm interpreter) -// ebx - Method* -// -void TemplateInterpreterGenerator::lock_method() { - __ ld(Lmethod, in_bytes(Method::access_flags_offset()), O0); // Load access flags. - -#ifdef ASSERT - { Label ok; - __ btst(JVM_ACC_SYNCHRONIZED, O0); - __ br( Assembler::notZero, false, Assembler::pt, ok); - __ delayed()->nop(); - __ stop("method doesn't need synchronization"); - __ bind(ok); - } -#endif // ASSERT - - // get synchronization object to O0 - { Label done; - __ btst(JVM_ACC_STATIC, O0); - __ br( Assembler::zero, true, Assembler::pt, done); - __ delayed()->ld_ptr(Llocals, Interpreter::local_offset_in_bytes(0), O0); // get receiver for not-static case - - // lock the mirror, not the Klass* - __ load_mirror(O0, Lmethod, Lscratch); - -#ifdef ASSERT - __ tst(O0); - __ breakpoint_trap(Assembler::zero, Assembler::ptr_cc); -#endif // ASSERT - - __ bind(done); - } - - __ add_monitor_to_stack(true, noreg, noreg); // allocate monitor elem - __ st_ptr( O0, Lmonitors, BasicObjectLock::obj_offset_in_bytes()); // store object - // __ untested("lock_object from method entry"); - __ lock_object(Lmonitors, O0); -} - -// See if we've got enough room on the stack for locals plus overhead below -// JavaThread::stack_overflow_limit(). If not, throw a StackOverflowError -// without going through the signal handler, i.e., reserved and yellow zones -// will not be made usable. The shadow zone must suffice to handle the -// overflow. -void TemplateInterpreterGenerator::generate_stack_overflow_check(Register Rframe_size, - Register Rscratch) { - const int page_size = os::vm_page_size(); - Label after_frame_check; - - assert_different_registers(Rframe_size, Rscratch); - - __ set(page_size, Rscratch); - __ cmp_and_br_short(Rframe_size, Rscratch, Assembler::lessEqual, Assembler::pt, after_frame_check); - - // Get the stack overflow limit, and in debug, verify it is non-zero. - __ ld_ptr(G2_thread, JavaThread::stack_overflow_limit_offset(), Rscratch); -#ifdef ASSERT - Label limit_ok; - __ br_notnull_short(Rscratch, Assembler::pn, limit_ok); - __ stop("stack overflow limit is zero in generate_stack_overflow_check"); - __ bind(limit_ok); -#endif - - // Add in the size of the frame (which is the same as subtracting it from the - // SP, which would take another register. - __ add(Rscratch, Rframe_size, Rscratch); - - // The frame is greater than one page in size, so check against - // the bottom of the stack. - __ cmp_and_brx_short(SP, Rscratch, Assembler::greaterUnsigned, Assembler::pt, after_frame_check); - - // The stack will overflow, throw an exception. - - // Note that SP is restored to sender's sp (in the delay slot). This - // is necessary if the sender's frame is an extended compiled frame - // (see gen_c2i_adapter()) and safer anyway in case of JSR292 - // adaptations. - - // Note also that the restored frame is not necessarily interpreted. - // Use the shared runtime version of the StackOverflowError. - assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated"); - AddressLiteral stub(StubRoutines::throw_StackOverflowError_entry()); - __ jump_to(stub, Rscratch); - __ delayed()->mov(O5_savedSP, SP); - - // If you get to here, then there is enough stack space. - __ bind(after_frame_check); -} - - -// -// Generate a fixed interpreter frame. This is identical setup for interpreted -// methods and for native methods hence the shared code. - - -//---------------------------------------------------------------------------------------------------- -// Stack frame layout -// -// When control flow reaches any of the entry types for the interpreter -// the following holds -> -// -// C2 Calling Conventions: -// -// The entry code below assumes that the following registers are set -// when coming in: -// G5_method: holds the Method* of the method to call -// Lesp: points to the TOS of the callers expression stack -// after having pushed all the parameters -// -// The entry code does the following to setup an interpreter frame -// pop parameters from the callers stack by adjusting Lesp -// set O0 to Lesp -// compute X = (max_locals - num_parameters) -// bump SP up by X to accommodate the extra locals -// compute X = max_expression_stack -// + vm_local_words -// + 16 words of register save area -// save frame doing a save sp, -X, sp growing towards lower addresses -// set Lbcp, Lmethod, LcpoolCache -// set Llocals to i0 -// set Lmonitors to FP - rounded_vm_local_words -// set Lesp to Lmonitors - 4 -// -// The frame has now been setup to do the rest of the entry code - -// Try this optimization: Most method entries could live in a -// "one size fits all" stack frame without all the dynamic size -// calculations. It might be profitable to do all this calculation -// statically and approximately for "small enough" methods. - -//----------------------------------------------------------------------------------------------- - -// C1 Calling conventions -// -// Upon method entry, the following registers are setup: -// -// g2 G2_thread: current thread -// g5 G5_method: method to activate -// g4 Gargs : pointer to last argument -// -// -// Stack: -// -// +---------------+ <--- sp -// | | -// : reg save area : -// | | -// +---------------+ <--- sp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- sp + 0x5c -// | | -// : free : -// | | -// +---------------+ <--- Gargs -// | | -// : arguments : -// | | -// +---------------+ -// | | -// -// -// -// AFTER FRAME HAS BEEN SETUP for method interpretation the stack looks like: -// -// +---------------+ <--- sp -// | | -// : reg save area : -// | | -// +---------------+ <--- sp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- sp + 0x5c -// | | -// : : -// | | <--- Lesp -// +---------------+ <--- Lmonitors (fp - 0x18) -// | VM locals | -// +---------------+ <--- fp -// | | -// : reg save area : -// | | -// +---------------+ <--- fp + 0x40 -// | | -// : extra 7 slots : note: these slots are not really needed for the interpreter (fix later) -// | | -// +---------------+ <--- fp + 0x5c -// | | -// : free : -// | | -// +---------------+ -// | | -// : nonarg locals : -// | | -// +---------------+ -// | | -// : arguments : -// | | <--- Llocals -// +---------------+ <--- Gargs -// | | - -void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { - // - // - // The entry code sets up a new interpreter frame in 4 steps: - // - // 1) Increase caller's SP by for the extra local space needed: - // (check for overflow) - // Efficient implementation of xload/xstore bytecodes requires - // that arguments and non-argument locals are in a contiguously - // addressable memory block => non-argument locals must be - // allocated in the caller's frame. - // - // 2) Create a new stack frame and register window: - // The new stack frame must provide space for the standard - // register save area, the maximum java expression stack size, - // the monitor slots (0 slots initially), and some frame local - // scratch locations. - // - // 3) The following interpreter activation registers must be setup: - // Lesp : expression stack pointer - // Lbcp : bytecode pointer - // Lmethod : method - // Llocals : locals pointer - // Lmonitors : monitor pointer - // LcpoolCache: constant pool cache - // - // 4) Initialize the non-argument locals if necessary: - // Non-argument locals may need to be initialized to NULL - // for GC to work. If the oop-map information is accurate - // (in the absence of the JSR problem), no initialization - // is necessary. - // - // (gri - 2/25/2000) - - - int rounded_vm_local_words = align_up((int)frame::interpreter_frame_vm_local_words, WordsPerLong ); - - const int extra_space = - rounded_vm_local_words + // frame local scratch space - Method::extra_stack_entries() + // extra stack for jsr 292 - frame::memory_parameter_word_sp_offset + // register save area - (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0); - - const Register Glocals_size = G3; - const Register RconstMethod = Glocals_size; - const Register Otmp1 = O3; - const Register Otmp2 = O4; - // Lscratch can't be used as a temporary because the call_stub uses - // it to assert that the stack frame was setup correctly. - const Address constMethod (G5_method, Method::const_offset()); - const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset()); - - __ ld_ptr( constMethod, RconstMethod ); - __ lduh( size_of_parameters, Glocals_size); - - // Gargs points to first local + BytesPerWord - // Set the saved SP after the register window save - // - assert_different_registers(Gargs, Glocals_size, Gframe_size, O5_savedSP); - __ sll(Glocals_size, Interpreter::logStackElementSize, Otmp1); - __ add(Gargs, Otmp1, Gargs); - - if (native_call) { - __ calc_mem_param_words( Glocals_size, Gframe_size ); - __ add( Gframe_size, extra_space, Gframe_size); - __ round_to( Gframe_size, WordsPerLong ); - __ sll( Gframe_size, LogBytesPerWord, Gframe_size ); - - // Native calls don't need the stack size check since they have no - // expression stack and the arguments are already on the stack and - // we only add a handful of words to the stack. - } else { - - // - // Compute number of locals in method apart from incoming parameters - // - const Address size_of_locals(Otmp1, ConstMethod::size_of_locals_offset()); - __ ld_ptr(constMethod, Otmp1); - __ lduh(size_of_locals, Otmp1); - __ sub(Otmp1, Glocals_size, Glocals_size); - __ round_to(Glocals_size, WordsPerLong); - __ sll(Glocals_size, Interpreter::logStackElementSize, Glocals_size); - - // See if the frame is greater than one page in size. If so, - // then we need to verify there is enough stack space remaining. - // Frame_size = (max_stack + extra_space) * BytesPerWord; - __ ld_ptr(constMethod, Gframe_size); - __ lduh(Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size); - __ add(Gframe_size, extra_space, Gframe_size); - __ round_to(Gframe_size, WordsPerLong); - __ sll(Gframe_size, Interpreter::logStackElementSize, Gframe_size); - - // Add in java locals size for stack overflow check only - __ add(Gframe_size, Glocals_size, Gframe_size); - - const Register Otmp2 = O4; - assert_different_registers(Otmp1, Otmp2, O5_savedSP); - generate_stack_overflow_check(Gframe_size, Otmp1); - - __ sub(Gframe_size, Glocals_size, Gframe_size); - - // - // bump SP to accommodate the extra locals - // - __ sub(SP, Glocals_size, SP); - } - - // - // now set up a stack frame with the size computed above - // - __ neg( Gframe_size ); - __ save( SP, Gframe_size, SP ); - - // - // now set up all the local cache registers - // - // NOTE: At this point, Lbyte_code/Lscratch has been modified. Note - // that all present references to Lbyte_code initialize the register - // immediately before use - if (native_call) { - __ mov(G0, Lbcp); - } else { - __ ld_ptr(G5_method, Method::const_offset(), Lbcp); - __ add(Lbcp, in_bytes(ConstMethod::codes_offset()), Lbcp); - } - __ mov( G5_method, Lmethod); // set Lmethod - // Get mirror and store it in the frame as GC root for this Method* - Register mirror = LcpoolCache; - __ load_mirror(mirror, Lmethod, Lscratch); - __ st_ptr(mirror, FP, (frame::interpreter_frame_mirror_offset * wordSize) + STACK_BIAS); - __ get_constant_pool_cache(LcpoolCache); // set LcpoolCache - __ sub(FP, rounded_vm_local_words * BytesPerWord, Lmonitors ); // set Lmonitors - __ add(Lmonitors, STACK_BIAS, Lmonitors); // Account for 64 bit stack bias - __ sub(Lmonitors, BytesPerWord, Lesp); // set Lesp - - // setup interpreter activation registers - __ sub(Gargs, BytesPerWord, Llocals); // set Llocals - - if (ProfileInterpreter) { - __ set_method_data_pointer(); - } - -} - -// Method entry for java.lang.ref.Reference.get. -address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { - // Code: _aload_0, _getfield, _areturn - // parameter size = 1 - // - // The code that gets generated by this routine is split into 2 parts: - // 1. The "intrinsified" code performing an ON_WEAK_OOP_REF load, - // 2. The slow path - which is an expansion of the regular method entry. - // - // Notes:- - // * An intrinsic is always executed, where an ON_WEAK_OOP_REF load is performed. - // * We may jump to the slow path iff the receiver is null. If the - // Reference object is null then we no longer perform an ON_WEAK_OOP_REF load - // Thus we can use the regular method entry code to generate the NPE. - // - // This code is based on generate_accessor_enty. - - address entry = __ pc(); - - const int referent_offset = java_lang_ref_Reference::referent_offset; - guarantee(referent_offset > 0, "referent offset not initialized"); - - Label slow_path; - - // In the G1 code we don't check if we need to reach a safepoint. We - // continue and the thread will safepoint at the next bytecode dispatch. - - // Check if local 0 != NULL - // If the receiver is null then it is OK to jump to the slow path. - __ ld_ptr(Gargs, G0, Otos_i ); // get local 0 - // check if local 0 == NULL and go the slow path - __ cmp_and_brx_short(Otos_i, 0, Assembler::equal, Assembler::pn, slow_path); - - __ load_heap_oop(Otos_i, referent_offset, Otos_i, G3_scratch, ON_WEAK_OOP_REF); - - // _areturn - __ retl(); // return from leaf routine - __ delayed()->mov(O5_savedSP, SP); - - // Generate regular method entry - __ bind(slow_path); - __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); - return entry; -} - -/** - * Method entry for static native methods: - * int java.util.zip.CRC32.update(int crc, int b) - */ -address TemplateInterpreterGenerator::generate_CRC32_update_entry() { - - if (UseCRC32Intrinsics) { - address entry = __ pc(); - - Label L_slow_path; - // If we need a safepoint check, generate full interpreter entry. - __ safepoint_poll(L_slow_path, false, G2_thread, O2); - __ delayed()->nop(); - - // Load parameters - const Register crc = O0; // initial crc - const Register val = O1; // byte to update with - const Register table = O2; // address of 256-entry lookup table - - __ ldub(Gargs, 3, val); - __ lduw(Gargs, 8, crc); - - __ set(ExternalAddress(StubRoutines::crc_table_addr()), table); - - __ not1(crc); // ~crc - __ clruwu(crc); - __ update_byte_crc32(crc, val, table); - __ not1(crc); // ~crc - - // result in O0 - __ retl(); - __ delayed()->nop(); - - // generate a vanilla native entry as the slow path - __ bind(L_slow_path); - __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); - return entry; - } - return NULL; -} - -/** - * Method entry for static native methods: - * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) - * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) - */ -address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { - - if (UseCRC32Intrinsics) { - address entry = __ pc(); - - Label L_slow_path; - // If we need a safepoint check, generate full interpreter entry. - - __ safepoint_poll(L_slow_path, false, G2_thread, O2); - __ delayed()->nop(); - - // Load parameters from the stack - const Register crc = O0; // initial crc - const Register buf = O1; // source java byte array address - const Register len = O2; // len - const Register offset = O3; // offset - - // Arguments are reversed on java expression stack - // Calculate address of start element - if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { - __ lduw(Gargs, 0, len); - __ lduw(Gargs, 8, offset); - __ ldx( Gargs, 16, buf); - __ lduw(Gargs, 32, crc); - __ add(buf, offset, buf); - } else { - __ lduw(Gargs, 0, len); - __ lduw(Gargs, 8, offset); - __ ldx( Gargs, 16, buf); - __ lduw(Gargs, 24, crc); - __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size - __ add(buf, offset, buf); - } - - // Call the crc32 kernel - __ MacroAssembler::save_thread(L7_thread_cache); - __ kernel_crc32(crc, buf, len, O3); - __ MacroAssembler::restore_thread(L7_thread_cache); - - // result in O0 - __ retl(); - __ delayed()->nop(); - - // generate a vanilla native entry as the slow path - __ bind(L_slow_path); - __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::native)); - return entry; - } - return NULL; -} - -/** - * Method entry for intrinsic-candidate (non-native) methods: - * int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) - * int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long buf, int off, int end) - * Unlike CRC32, CRC32C does not have any methods marked as native - * CRC32C also uses an "end" variable instead of the length variable CRC32 uses - */ -address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { - - if (UseCRC32CIntrinsics) { - address entry = __ pc(); - - // Load parameters from the stack - const Register crc = O0; // initial crc - const Register buf = O1; // source java byte array address - const Register offset = O2; // offset - const Register end = O3; // index of last element to process - const Register len = O2; // len argument to the kernel - const Register table = O3; // crc32c lookup table address - - // Arguments are reversed on java expression stack - // Calculate address of start element - if (kind == Interpreter::java_util_zip_CRC32C_updateDirectByteBuffer) { - __ lduw(Gargs, 0, end); - __ lduw(Gargs, 8, offset); - __ ldx( Gargs, 16, buf); - __ lduw(Gargs, 32, crc); - __ add(buf, offset, buf); - __ sub(end, offset, len); - } else { - __ lduw(Gargs, 0, end); - __ lduw(Gargs, 8, offset); - __ ldx( Gargs, 16, buf); - __ lduw(Gargs, 24, crc); - __ add(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE), buf); // account for the header size - __ add(buf, offset, buf); - __ sub(end, offset, len); - } - - // Call the crc32c kernel - __ MacroAssembler::save_thread(L7_thread_cache); - __ kernel_crc32c(crc, buf, len, table); - __ MacroAssembler::restore_thread(L7_thread_cache); - - // result in O0 - __ retl(); - __ delayed()->nop(); - - return entry; - } - return NULL; -} - -/* Math routines only partially supported. - * - * Providing support for fma (float/double) only. - */ -address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) -{ - if (!InlineIntrinsics) return NULL; // Generate a vanilla entry - - address entry = __ pc(); - - switch (kind) { - case Interpreter::java_lang_math_fmaF: - if (UseFMA) { - // float .fma(float a, float b, float c) - const FloatRegister ra = F1; - const FloatRegister rb = F2; - const FloatRegister rc = F3; - const FloatRegister rd = F0; // Result. - - __ ldf(FloatRegisterImpl::S, Gargs, 0, rc); - __ ldf(FloatRegisterImpl::S, Gargs, 8, rb); - __ ldf(FloatRegisterImpl::S, Gargs, 16, ra); - - __ fmadd(FloatRegisterImpl::S, ra, rb, rc, rd); - __ retl(); // Result in F0 (rd). - __ delayed()->mov(O5_savedSP, SP); - - return entry; - } - break; - case Interpreter::java_lang_math_fmaD: - if (UseFMA) { - // double .fma(double a, double b, double c) - const FloatRegister ra = F2; // D1 - const FloatRegister rb = F4; // D2 - const FloatRegister rc = F6; // D3 - const FloatRegister rd = F0; // D0 Result. - - __ ldf(FloatRegisterImpl::D, Gargs, 0, rc); - __ ldf(FloatRegisterImpl::D, Gargs, 16, rb); - __ ldf(FloatRegisterImpl::D, Gargs, 32, ra); - - __ fmadd(FloatRegisterImpl::D, ra, rb, rc, rd); - __ retl(); // Result in D0 (rd). - __ delayed()->mov(O5_savedSP, SP); - - return entry; - } - break; - default: - break; - } - return NULL; -} - -// TODO: rather than touching all pages, check against stack_overflow_limit and bang yellow page to -// generate exception -void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { - // Quick & dirty stack overflow checking: bang the stack & handle trap. - // Note that we do the banging after the frame is setup, since the exception - // handling code expects to find a valid interpreter frame on the stack. - // Doing the banging earlier fails if the caller frame is not an interpreter - // frame. - // (Also, the exception throwing code expects to unlock any synchronized - // method receiver, so do the banging after locking the receiver.) - - // Bang each page in the shadow zone. We can't assume it's been done for - // an interpreter frame with greater than a page of locals, so each page - // needs to be checked. Only true for non-native. - if (UseStackBanging) { - const int page_size = os::vm_page_size(); - const int n_shadow_pages = ((int)JavaThread::stack_shadow_zone_size()) / page_size; - const int start_page = native_call ? n_shadow_pages : 1; - for (int pages = start_page; pages <= n_shadow_pages; pages++) { - __ bang_stack_with_offset(pages*page_size); - } - } -} - -// -// Interpreter stub for calling a native method. (asm interpreter) -// This sets up a somewhat different looking stack for calling the native method -// than the typical interpreter frame setup. -// - -address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { - address entry = __ pc(); - - // the following temporary registers are used during frame creation - const Register Gtmp1 = G3_scratch ; - const Register Gtmp2 = G1_scratch; - bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; - - // make sure registers are different! - assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2); - - const Address Laccess_flags(Lmethod, Method::access_flags_offset()); - - const Register Glocals_size = G3; - assert_different_registers(Glocals_size, G4_scratch, Gframe_size); - - // make sure method is native & not abstract - // rethink these assertions - they can be simplified and shared (gri 2/25/2000) -#ifdef ASSERT - __ ld(G5_method, Method::access_flags_offset(), Gtmp1); - { Label L; - __ btst(JVM_ACC_NATIVE, Gtmp1); - __ br(Assembler::notZero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("tried to execute non-native method as native"); - __ bind(L); - } - { Label L; - __ btst(JVM_ACC_ABSTRACT, Gtmp1); - __ br(Assembler::zero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("tried to execute abstract method as non-abstract"); - __ bind(L); - } -#endif // ASSERT - - // generate the code to allocate the interpreter stack frame - generate_fixed_frame(true); - - // - // No locals to initialize for native method - // - - // this slot will be set later, we initialize it to null here just in - // case we get a GC before the actual value is stored later - __ st_ptr(G0, FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS); - - const Address do_not_unlock_if_synchronized(G2_thread, - JavaThread::do_not_unlock_if_synchronized_offset()); - // Since at this point in the method invocation the exception handler - // would try to exit the monitor of synchronized methods which hasn't - // been entered yet, we set the thread local variable - // _do_not_unlock_if_synchronized to true. If any exception was thrown by - // runtime, exception handling i.e. unlock_if_synchronized_method will - // check this thread local flag. - // This flag has two effects, one is to force an unwind in the topmost - // interpreter frame and not perform an unlock while doing so. - - __ movbool(true, G3_scratch); - __ stbool(G3_scratch, do_not_unlock_if_synchronized); - - // increment invocation counter and check for overflow - // - // Note: checking for negative value instead of overflow - // so we have a 'sticky' overflow test (may be of - // importance as soon as we have true MT/MP) - Label invocation_counter_overflow; - Label Lcontinue; - if (inc_counter) { - generate_counter_incr(&invocation_counter_overflow, NULL, NULL); - - } - __ bind(Lcontinue); - - bang_stack_shadow_pages(true); - - // reset the _do_not_unlock_if_synchronized flag - __ stbool(G0, do_not_unlock_if_synchronized); - - // check for synchronized methods - // Must happen AFTER invocation_counter check and stack overflow check, - // so method is not locked if overflows. - - if (synchronized) { - lock_method(); - } else { -#ifdef ASSERT - { Label ok; - __ ld(Laccess_flags, O0); - __ btst(JVM_ACC_SYNCHRONIZED, O0); - __ br( Assembler::zero, false, Assembler::pt, ok); - __ delayed()->nop(); - __ stop("method needs synchronization"); - __ bind(ok); - } -#endif // ASSERT - } - - - // start execution - __ verify_thread(); - - // JVMTI support - __ notify_method_entry(); - - // native call - - // (note that O0 is never an oop--at most it is a handle) - // It is important not to smash any handles created by this call, - // until any oop handle in O0 is dereferenced. - - // (note that the space for outgoing params is preallocated) - - // get signature handler - { Label L; - Address signature_handler(Lmethod, Method::signature_handler_offset()); - __ ld_ptr(signature_handler, G3_scratch); - __ br_notnull_short(G3_scratch, Assembler::pt, L); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), Lmethod); - __ ld_ptr(signature_handler, G3_scratch); - __ bind(L); - } - - // Push a new frame so that the args will really be stored in - // Copy a few locals across so the new frame has the variables - // we need but these values will be dead at the jni call and - // therefore not gc volatile like the values in the current - // frame (Lmethod in particular) - - // Flush the method pointer to the register save area - __ st_ptr(Lmethod, SP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS); - __ mov(Llocals, O1); - - // calculate where the mirror handle body is allocated in the interpreter frame: - __ add(FP, (frame::interpreter_frame_oop_temp_offset * wordSize) + STACK_BIAS, O2); - - // Calculate current frame size - __ sub(SP, FP, O3); // Calculate negative of current frame size - __ save(SP, O3, SP); // Allocate an identical sized frame - - // Note I7 has leftover trash. Slow signature handler will fill it in - // should we get there. Normal jni call will set reasonable last_Java_pc - // below (and fix I7 so the stack trace doesn't have a meaningless frame - // in it). - - // Load interpreter frame's Lmethod into same register here - - __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod); - - __ mov(I1, Llocals); - __ mov(I2, Lscratch2); // save the address of the mirror - - - // ONLY Lmethod and Llocals are valid here! - - // call signature handler, It will move the arg properly since Llocals in current frame - // matches that in outer frame - - __ callr(G3_scratch, 0); - __ delayed()->nop(); - - // Result handler is in Lscratch - - // Reload interpreter frame's Lmethod since slow signature handler may block - __ ld_ptr(FP, (Lmethod->sp_offset_in_saved_window() * wordSize) + STACK_BIAS, Lmethod); - - { Label not_static; - - __ ld(Laccess_flags, O0); - __ btst(JVM_ACC_STATIC, O0); - __ br( Assembler::zero, false, Assembler::pt, not_static); - // get native function entry point(O0 is a good temp until the very end) - __ delayed()->ld_ptr(Lmethod, in_bytes(Method::native_function_offset()), O0); - // for static methods insert the mirror argument - __ load_mirror(O1, Lmethod, G3_scratch); -#ifdef ASSERT - if (!PrintSignatureHandlers) // do not dirty the output with this - { Label L; - __ br_notnull_short(O1, Assembler::pt, L); - __ stop("mirror is missing"); - __ bind(L); - } -#endif // ASSERT - __ st_ptr(O1, Lscratch2, 0); - __ mov(Lscratch2, O1); - __ bind(not_static); - } - - // At this point, arguments have been copied off of stack into - // their JNI positions, which are O1..O5 and SP[68..]. - // Oops are boxed in-place on the stack, with handles copied to arguments. - // The result handler is in Lscratch. O0 will shortly hold the JNIEnv*. - -#ifdef ASSERT - { Label L; - __ br_notnull_short(O0, Assembler::pt, L); - __ stop("native entry point is missing"); - __ bind(L); - } -#endif // ASSERT - - // - // setup the frame anchor - // - // The scavenge function only needs to know that the PC of this frame is - // in the interpreter method entry code, it doesn't need to know the exact - // PC and hence we can use O7 which points to the return address from the - // previous call in the code stream (signature handler function) - // - // The other trick is we set last_Java_sp to FP instead of the usual SP because - // we have pushed the extra frame in order to protect the volatile register(s) - // in that frame when we return from the jni call - // - - __ set_last_Java_frame(FP, O7); - __ mov(O7, I7); // make dummy interpreter frame look like one above, - // not meaningless information that'll confuse me. - - // flush the windows now. We don't care about the current (protection) frame - // only the outer frames - - __ flushw(); - - // mark windows as flushed - Address flags(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset()); - __ set(JavaFrameAnchor::flushed, G3_scratch); - __ st(G3_scratch, flags); - - // Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready. - - Address thread_state(G2_thread, JavaThread::thread_state_offset()); -#ifdef ASSERT - { Label L; - __ ld(thread_state, G3_scratch); - __ cmp_and_br_short(G3_scratch, _thread_in_Java, Assembler::equal, Assembler::pt, L); - __ stop("Wrong thread state in native stub"); - __ bind(L); - } -#endif // ASSERT - __ set(_thread_in_native, G3_scratch); - __ st(G3_scratch, thread_state); - - // Call the jni method, using the delay slot to set the JNIEnv* argument. - __ save_thread(L7_thread_cache); // save Gthread - __ callr(O0, 0); - __ delayed()-> - add(L7_thread_cache, in_bytes(JavaThread::jni_environment_offset()), O0); - - // Back from jni method Lmethod in this frame is DEAD, DEAD, DEAD - - __ restore_thread(L7_thread_cache); // restore G2_thread - __ reinit_heapbase(); - - // must we block? - - // Block, if necessary, before resuming in _thread_in_Java state. - // In order for GC to work, don't clear the last_Java_sp until after blocking. - { Label no_block; - - // Switch thread to "native transition" state before reading the synchronization state. - // This additional state is necessary because reading and testing the synchronization - // state is not atomic w.r.t. GC, as this scenario demonstrates: - // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. - // VM thread changes sync state to synchronizing and suspends threads for GC. - // Thread A is resumed to finish this native method, but doesn't block here since it - // didn't see any synchronization is progress, and escapes. - __ set(_thread_in_native_trans, G3_scratch); - __ st(G3_scratch, thread_state); - - // Force this write out before the read below - __ membar(Assembler::StoreLoad); - - Label L; - __ safepoint_poll(L, false, G2_thread, G3_scratch); - __ delayed()->ld(G2_thread, JavaThread::suspend_flags_offset(), G3_scratch); - __ cmp_and_br_short(G3_scratch, 0, Assembler::equal, Assembler::pt, no_block); - __ bind(L); - - // Block. Save any potential method result value before the operation and - // use a leaf call to leave the last_Java_frame setup undisturbed. - save_native_result(); - __ call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), - G2_thread); - - // Restore any method result value - restore_native_result(); - __ bind(no_block); - } - - // Clear the frame anchor now - - __ reset_last_Java_frame(); - - // Move the result handler address - __ mov(Lscratch, G3_scratch); - // return possible result to the outer frame - __ restore(O0, G0, O0); - - // Move result handler to expected register - __ mov(G3_scratch, Lscratch); - - // Back in normal (native) interpreter frame. State is thread_in_native_trans - // switch to thread_in_Java. - - __ set(_thread_in_Java, G3_scratch); - __ st(G3_scratch, thread_state); - - if (CheckJNICalls) { - // clear_pending_jni_exception_check - __ st_ptr(G0, G2_thread, JavaThread::pending_jni_exception_check_fn_offset()); - } - - // reset handle block - __ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch); - __ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes()); - - // If we have an oop result store it where it will be safe for any further gc - // until we return now that we've released the handle it might be protected by - - { Label no_oop; - - __ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch); - __ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop); - __ resolve_jobject(O0, G3_scratch); - // Store it where gc will look for it and result handler expects it. - __ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS); - - __ bind(no_oop); - } - - - // handle exceptions (exception handling will handle unlocking!) - { Label L; - Address exception_addr(G2_thread, Thread::pending_exception_offset()); - __ ld_ptr(exception_addr, Gtemp); - __ br_null_short(Gtemp, Assembler::pt, L); - // Note: This could be handled more efficiently since we know that the native - // method doesn't have an exception handler. We could directly return - // to the exception handler for the caller. - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception)); - __ should_not_reach_here(); - __ bind(L); - } - - // JVMTI support (preserves thread register) - __ notify_method_exit(true, ilgl, InterpreterMacroAssembler::NotifyJVMTI); - - if (synchronized) { - // save and restore any potential method result value around the unlocking operation - save_native_result(); - - __ add( __ top_most_monitor(), O1); - __ unlock_object(O1); - - restore_native_result(); - } - - // dispose of return address and remove activation -#ifdef ASSERT - { Label ok; - __ cmp_and_brx_short(I5_savedSP, FP, Assembler::greaterEqualUnsigned, Assembler::pt, ok); - __ stop("bad I5_savedSP value"); - __ should_not_reach_here(); - __ bind(ok); - } -#endif - __ jmp(Lscratch, 0); - __ delayed()->nop(); - - if (inc_counter) { - // handle invocation counter overflow - __ bind(invocation_counter_overflow); - generate_counter_overflow(Lcontinue); - } - - return entry; -} - - -// Generic method entry to (asm) interpreter -address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { - address entry = __ pc(); - - bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; - - // the following temporary registers are used during frame creation - const Register Gtmp1 = G3_scratch ; - const Register Gtmp2 = G1_scratch; - - // make sure registers are different! - assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2); - - const Address constMethod (G5_method, Method::const_offset()); - // Seems like G5_method is live at the point this is used. So we could make this look consistent - // and use in the asserts. - const Address access_flags (Lmethod, Method::access_flags_offset()); - - const Register Glocals_size = G3; - assert_different_registers(Glocals_size, G4_scratch, Gframe_size); - - // make sure method is not native & not abstract - // rethink these assertions - they can be simplified and shared (gri 2/25/2000) -#ifdef ASSERT - __ ld(G5_method, Method::access_flags_offset(), Gtmp1); - { Label L; - __ btst(JVM_ACC_NATIVE, Gtmp1); - __ br(Assembler::zero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("tried to execute native method as non-native"); - __ bind(L); - } - { Label L; - __ btst(JVM_ACC_ABSTRACT, Gtmp1); - __ br(Assembler::zero, false, Assembler::pt, L); - __ delayed()->nop(); - __ stop("tried to execute abstract method as non-abstract"); - __ bind(L); - } -#endif // ASSERT - - // generate the code to allocate the interpreter stack frame - - generate_fixed_frame(false); - - // - // Code to initialize the extra (i.e. non-parm) locals - // - Register init_value = noreg; // will be G0 if we must clear locals - // The way the code was setup before zerolocals was always true for vanilla java entries. - // It could only be false for the specialized entries like accessor or empty which have - // no extra locals so the testing was a waste of time and the extra locals were always - // initialized. We removed this extra complication to already over complicated code. - - init_value = G0; - Label clear_loop; - - const Register RconstMethod = O1; - const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset()); - const Address size_of_locals (RconstMethod, ConstMethod::size_of_locals_offset()); - - // NOTE: If you change the frame layout, this code will need to - // be updated! - __ ld_ptr( constMethod, RconstMethod ); - __ lduh( size_of_locals, O2 ); - __ lduh( size_of_parameters, O1 ); - __ sll( O2, Interpreter::logStackElementSize, O2); - __ sll( O1, Interpreter::logStackElementSize, O1 ); - __ sub( Llocals, O2, O2 ); - __ sub( Llocals, O1, O1 ); - - __ bind( clear_loop ); - __ inc( O2, wordSize ); - - __ cmp( O2, O1 ); - __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, clear_loop ); - __ delayed()->st_ptr( init_value, O2, 0 ); - - const Address do_not_unlock_if_synchronized(G2_thread, - JavaThread::do_not_unlock_if_synchronized_offset()); - // Since at this point in the method invocation the exception handler - // would try to exit the monitor of synchronized methods which hasn't - // been entered yet, we set the thread local variable - // _do_not_unlock_if_synchronized to true. If any exception was thrown by - // runtime, exception handling i.e. unlock_if_synchronized_method will - // check this thread local flag. - __ movbool(true, G3_scratch); - __ stbool(G3_scratch, do_not_unlock_if_synchronized); - - __ profile_parameters_type(G1_scratch, G3_scratch, G4_scratch, Lscratch); - // increment invocation counter and check for overflow - // - // Note: checking for negative value instead of overflow - // so we have a 'sticky' overflow test (may be of - // importance as soon as we have true MT/MP) - Label invocation_counter_overflow; - Label profile_method; - Label profile_method_continue; - Label Lcontinue; - if (inc_counter) { - generate_counter_incr(&invocation_counter_overflow, &profile_method, &profile_method_continue); - if (ProfileInterpreter) { - __ bind(profile_method_continue); - } - } - __ bind(Lcontinue); - - bang_stack_shadow_pages(false); - - // reset the _do_not_unlock_if_synchronized flag - __ stbool(G0, do_not_unlock_if_synchronized); - - // check for synchronized methods - // Must happen AFTER invocation_counter check and stack overflow check, - // so method is not locked if overflows. - - if (synchronized) { - lock_method(); - } else { -#ifdef ASSERT - { Label ok; - __ ld(access_flags, O0); - __ btst(JVM_ACC_SYNCHRONIZED, O0); - __ br( Assembler::zero, false, Assembler::pt, ok); - __ delayed()->nop(); - __ stop("method needs synchronization"); - __ bind(ok); - } -#endif // ASSERT - } - - // start execution - - __ verify_thread(); - - // jvmti support - __ notify_method_entry(); - - // start executing instructions - __ dispatch_next(vtos); - - - if (inc_counter) { - if (ProfileInterpreter) { - // We have decided to profile this method in the interpreter - __ bind(profile_method); - - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::profile_method)); - __ set_method_data_pointer_for_bcp(); - __ ba_short(profile_method_continue); - } - - // handle invocation counter overflow - __ bind(invocation_counter_overflow); - generate_counter_overflow(Lcontinue); - } - - return entry; -} - -//---------------------------------------------------------------------------------------------------- -// Exceptions -void TemplateInterpreterGenerator::generate_throw_exception() { - - // Entry point in previous activation (i.e., if the caller was interpreted) - Interpreter::_rethrow_exception_entry = __ pc(); - // O0: exception - - // entry point for exceptions thrown within interpreter code - Interpreter::_throw_exception_entry = __ pc(); - __ verify_thread(); - // expression stack is undefined here - // O0: exception, i.e. Oexception - // Lbcp: exception bcp - __ verify_oop(Oexception); - - - // expression stack must be empty before entering the VM in case of an exception - __ empty_expression_stack(); - // find exception handler address and preserve exception oop - // call C routine to find handler and jump to it - __ call_VM(O1, CAST_FROM_FN_PTR(address, InterpreterRuntime::exception_handler_for_exception), Oexception); - __ push_ptr(O1); // push exception for exception handler bytecodes - - __ JMP(O0, 0); // jump to exception handler (may be remove activation entry!) - __ delayed()->nop(); - - - // if the exception is not handled in the current frame - // the frame is removed and the exception is rethrown - // (i.e. exception continuation is _rethrow_exception) - // - // Note: At this point the bci is still the bxi for the instruction which caused - // the exception and the expression stack is empty. Thus, for any VM calls - // at this point, GC will find a legal oop map (with empty expression stack). - - // in current activation - // tos: exception - // Lbcp: exception bcp - - // - // JVMTI PopFrame support - // - - Interpreter::_remove_activation_preserving_args_entry = __ pc(); - Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset()); - // Set the popframe_processing bit in popframe_condition indicating that we are - // currently handling popframe, so that call_VMs that may happen later do not trigger new - // popframe handling cycles. - - __ ld(popframe_condition_addr, G3_scratch); - __ or3(G3_scratch, JavaThread::popframe_processing_bit, G3_scratch); - __ stw(G3_scratch, popframe_condition_addr); - - // Empty the expression stack, as in normal exception handling - __ empty_expression_stack(); - __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false, /* install_monitor_exception */ false); - - { - // Check to see whether we are returning to a deoptimized frame. - // (The PopFrame call ensures that the caller of the popped frame is - // either interpreted or compiled and deoptimizes it if compiled.) - // In this case, we can't call dispatch_next() after the frame is - // popped, but instead must save the incoming arguments and restore - // them after deoptimization has occurred. - // - // Note that we don't compare the return PC against the - // deoptimization blob's unpack entry because of the presence of - // adapter frames in C2. - Label caller_not_deoptimized; - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), I7); - __ br_notnull_short(O0, Assembler::pt, caller_not_deoptimized); - - const Register Gtmp1 = G3_scratch; - const Register Gtmp2 = G1_scratch; - const Register RconstMethod = Gtmp1; - const Address constMethod(Lmethod, Method::const_offset()); - const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset()); - - // Compute size of arguments for saving when returning to deoptimized caller - __ ld_ptr(constMethod, RconstMethod); - __ lduh(size_of_parameters, Gtmp1); - __ sll(Gtmp1, Interpreter::logStackElementSize, Gtmp1); - __ sub(Llocals, Gtmp1, Gtmp2); - __ add(Gtmp2, wordSize, Gtmp2); - // Save these arguments - __ call_VM_leaf(L7_thread_cache, CAST_FROM_FN_PTR(address, Deoptimization::popframe_preserve_args), G2_thread, Gtmp1, Gtmp2); - // Inform deoptimization that it is responsible for restoring these arguments - __ set(JavaThread::popframe_force_deopt_reexecution_bit, Gtmp1); - Address popframe_condition_addr(G2_thread, JavaThread::popframe_condition_offset()); - __ st(Gtmp1, popframe_condition_addr); - - // Return from the current method - // The caller's SP was adjusted upon method entry to accomodate - // the callee's non-argument locals. Undo that adjustment. - __ ret(); - __ delayed()->restore(I5_savedSP, G0, SP); - - __ bind(caller_not_deoptimized); - } - - // Clear the popframe condition flag - __ stw(G0 /* popframe_inactive */, popframe_condition_addr); - - // Get out of the current method (how this is done depends on the particular compiler calling - // convention that the interpreter currently follows) - // The caller's SP was adjusted upon method entry to accomodate - // the callee's non-argument locals. Undo that adjustment. - __ restore(I5_savedSP, G0, SP); - // The method data pointer was incremented already during - // call profiling. We have to restore the mdp for the current bcp. - if (ProfileInterpreter) { - __ set_method_data_pointer_for_bcp(); - } - -#if INCLUDE_JVMTI - { Label L_done; - - __ ldub(Address(Lbcp, 0), G1_scratch); // Load current bytecode - __ cmp_and_br_short(G1_scratch, Bytecodes::_invokestatic, Assembler::notEqual, Assembler::pn, L_done); - - // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call. - // Detect such a case in the InterpreterRuntime function and return the member name argument, or NULL. - - __ call_VM(G1_scratch, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null), I0, Lmethod, Lbcp); - - __ br_null(G1_scratch, false, Assembler::pn, L_done); - __ delayed()->nop(); - - __ st_ptr(G1_scratch, Lesp, wordSize); - __ bind(L_done); - } -#endif // INCLUDE_JVMTI - - // Resume bytecode interpretation at the current bcp - __ dispatch_next(vtos); - // end of JVMTI PopFrame support - - Interpreter::_remove_activation_entry = __ pc(); - - // preserve exception over this code sequence (remove activation calls the vm, but oopmaps are not correct here) - __ pop_ptr(Oexception); // get exception - - // Intel has the following comment: - //// remove the activation (without doing throws on illegalMonitorExceptions) - // They remove the activation without checking for bad monitor state. - // %%% We should make sure this is the right semantics before implementing. - - __ set_vm_result(Oexception); - __ unlock_if_synchronized_method(vtos, /* throw_monitor_exception */ false); - - __ notify_method_exit(false, vtos, InterpreterMacroAssembler::SkipNotifyJVMTI); - - __ get_vm_result(Oexception); - __ verify_oop(Oexception); - - const int return_reg_adjustment = frame::pc_return_offset; - Address issuing_pc_addr(I7, return_reg_adjustment); - - // We are done with this activation frame; find out where to go next. - // The continuation point will be an exception handler, which expects - // the following registers set up: - // - // Oexception: exception - // Oissuing_pc: the local call that threw exception - // Other On: garbage - // In/Ln: the contents of the caller's register window - // - // We do the required restore at the last possible moment, because we - // need to preserve some state across a runtime call. - // (Remember that the caller activation is unknown--it might not be - // interpreted, so things like Lscratch are useless in the caller.) - - // Although the Intel version uses call_C, we can use the more - // compact call_VM. (The only real difference on SPARC is a - // harmlessly ignored [re]set_last_Java_frame, compared with - // the Intel code which lacks this.) - __ mov(Oexception, Oexception ->after_save()); // get exception in I0 so it will be on O0 after restore - __ add(issuing_pc_addr, Oissuing_pc->after_save()); // likewise set I1 to a value local to the caller - __ super_call_VM_leaf(L7_thread_cache, - CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), - G2_thread, Oissuing_pc->after_save()); - - // The caller's SP was adjusted upon method entry to accomodate - // the callee's non-argument locals. Undo that adjustment. - __ JMP(O0, 0); // return exception handler in caller - __ delayed()->restore(I5_savedSP, G0, SP); - - // (same old exception object is already in Oexception; see above) - // Note that an "issuing PC" is actually the next PC after the call -} - - -// -// JVMTI ForceEarlyReturn support -// - -address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) { - address entry = __ pc(); - - __ empty_expression_stack(); - __ load_earlyret_value(state); - - __ ld_ptr(G2_thread, JavaThread::jvmti_thread_state_offset(), G3_scratch); - Address cond_addr(G3_scratch, JvmtiThreadState::earlyret_state_offset()); - - // Clear the earlyret state - __ stw(G0 /* JvmtiThreadState::earlyret_inactive */, cond_addr); - - __ remove_activation(state, - /* throw_monitor_exception */ false, - /* install_monitor_exception */ false); - - // The caller's SP was adjusted upon method entry to accomodate - // the callee's non-argument locals. Undo that adjustment. - __ ret(); // return to caller - __ delayed()->restore(I5_savedSP, G0, SP); - - return entry; -} // end of JVMTI ForceEarlyReturn support - - -//------------------------------------------------------------------------------------------------------------------------ -// Helper for vtos entry point generation - -void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) { - assert(t->is_valid() && t->tos_in() == vtos, "illegal template"); - Label L; - aep = __ pc(); __ push_ptr(); __ ba_short(L); - fep = __ pc(); __ push_f(); __ ba_short(L); - dep = __ pc(); __ push_d(); __ ba_short(L); - lep = __ pc(); __ push_l(); __ ba_short(L); - iep = __ pc(); __ push_i(); - bep = cep = sep = iep; // there aren't any - vep = __ pc(); __ bind(L); // fall through - generate_and_dispatch(t); -} - -// -------------------------------------------------------------------------------- - -// Non-product code -#ifndef PRODUCT -address TemplateInterpreterGenerator::generate_trace_code(TosState state) { - address entry = __ pc(); - - __ push(state); - __ mov(O7, Lscratch); // protect return address within interpreter - - // Pass a 0 (not used in sparc) and the top of stack to the bytecode tracer - __ mov( Otos_l2, G3_scratch ); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), G0, Otos_l1, G3_scratch); - __ mov(Lscratch, O7); // restore return address - __ pop(state); - __ retl(); - __ delayed()->nop(); - - return entry; -} - - -// helpers for generate_and_dispatch - -void TemplateInterpreterGenerator::count_bytecode() { - __ inc_counter(&BytecodeCounter::_counter_value, G3_scratch, G4_scratch); -} - - -void TemplateInterpreterGenerator::histogram_bytecode(Template* t) { - __ inc_counter(&BytecodeHistogram::_counters[t->bytecode()], G3_scratch, G4_scratch); -} - - -void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { - AddressLiteral index (&BytecodePairHistogram::_index); - AddressLiteral counters((address) &BytecodePairHistogram::_counters); - - // get index, shift out old bytecode, bring in new bytecode, and store it - // _index = (_index >> log2_number_of_codes) | - // (bytecode << log2_number_of_codes); - - __ load_contents(index, G4_scratch); - __ srl( G4_scratch, BytecodePairHistogram::log2_number_of_codes, G4_scratch ); - __ set( ((int)t->bytecode()) << BytecodePairHistogram::log2_number_of_codes, G3_scratch ); - __ or3( G3_scratch, G4_scratch, G4_scratch ); - __ store_contents(G4_scratch, index, G3_scratch); - - // bump bucket contents - // _counters[_index] ++; - - __ set(counters, G3_scratch); // loads into G3_scratch - __ sll( G4_scratch, LogBytesPerWord, G4_scratch ); // Index is word address - __ add (G3_scratch, G4_scratch, G3_scratch); // Add in index - __ ld (G3_scratch, 0, G4_scratch); - __ inc (G4_scratch); - __ st (G4_scratch, 0, G3_scratch); -} - - -void TemplateInterpreterGenerator::trace_bytecode(Template* t) { - // Call a little run-time stub to avoid blow-up for each bytecode. - // The run-time runtime saves the right registers, depending on - // the tosca in-state for the given template. - address entry = Interpreter::trace_code(t->tos_in()); - guarantee(entry != NULL, "entry must have been generated"); - __ call(entry, relocInfo::none); - __ delayed()->nop(); -} - - -void TemplateInterpreterGenerator::stop_interpreter_at() { - AddressLiteral counter(&BytecodeCounter::_counter_value); - __ load_contents(counter, G3_scratch); - AddressLiteral stop_at(&StopInterpreterAt); - __ load_ptr_contents(stop_at, G4_scratch); - __ cmp(G3_scratch, G4_scratch); - __ breakpoint_trap(Assembler::equal, Assembler::icc); -} -#endif // not PRODUCT diff --git a/src/hotspot/cpu/sparc/templateTable_sparc.cpp b/src/hotspot/cpu/sparc/templateTable_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp +++ /dev/null @@ -1,3862 +0,0 @@ -/* - * Copyright (c) 1997, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "gc/shared/barrierSetAssembler.hpp" -#include "interpreter/interpreter.hpp" -#include "interpreter/interpreterRuntime.hpp" -#include "interpreter/interp_masm.hpp" -#include "interpreter/templateTable.hpp" -#include "memory/universe.hpp" -#include "oops/methodData.hpp" -#include "oops/objArrayKlass.hpp" -#include "oops/oop.inline.hpp" -#include "prims/methodHandles.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/synchronizer.hpp" -#include "utilities/macros.hpp" - -#define __ _masm-> - -// Misc helpers - -// Do an oop store like *(base + index + offset) = val -// index can be noreg, -static void do_oop_store(InterpreterMacroAssembler* _masm, - Register base, - Register index, - int offset, - Register val, - Register tmp, - DecoratorSet decorators = 0) { - assert(tmp != val && tmp != base && tmp != index, "register collision"); - assert(index == noreg || offset == 0, "only one offset"); - if (index == noreg) { - __ store_heap_oop(val, base, offset, tmp, decorators); - } else { - __ store_heap_oop(val, base, index, tmp, decorators); - } -} - -// Do an oop load like val = *(base + index + offset) -// index can be noreg. -static void do_oop_load(InterpreterMacroAssembler* _masm, - Register base, - Register index, - int offset, - Register dst, - Register tmp, - DecoratorSet decorators = 0) { - assert(tmp != dst && tmp != base && tmp != index, "register collision"); - assert(index == noreg || offset == 0, "only one offset"); - if (index == noreg) { - __ load_heap_oop(base, offset, dst, tmp, decorators); - } else { - __ load_heap_oop(base, index, dst, tmp, decorators); - } -} - - -//---------------------------------------------------------------------------------------------------- -// Platform-dependent initialization - -void TemplateTable::pd_initialize() { - // (none) -} - - -//---------------------------------------------------------------------------------------------------- -// Condition conversion -Assembler::Condition ccNot(TemplateTable::Condition cc) { - switch (cc) { - case TemplateTable::equal : return Assembler::notEqual; - case TemplateTable::not_equal : return Assembler::equal; - case TemplateTable::less : return Assembler::greaterEqual; - case TemplateTable::less_equal : return Assembler::greater; - case TemplateTable::greater : return Assembler::lessEqual; - case TemplateTable::greater_equal: return Assembler::less; - } - ShouldNotReachHere(); - return Assembler::zero; -} - -//---------------------------------------------------------------------------------------------------- -// Miscelaneous helper routines - - -Address TemplateTable::at_bcp(int offset) { - assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); - return Address(Lbcp, offset); -} - - -void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, - Register temp_reg, bool load_bc_into_bc_reg/*=true*/, - int byte_no) { - // With sharing on, may need to test Method* flag. - if (!RewriteBytecodes) return; - Label L_patch_done; - - switch (bc) { - case Bytecodes::_fast_aputfield: - case Bytecodes::_fast_bputfield: - case Bytecodes::_fast_zputfield: - case Bytecodes::_fast_cputfield: - case Bytecodes::_fast_dputfield: - case Bytecodes::_fast_fputfield: - case Bytecodes::_fast_iputfield: - case Bytecodes::_fast_lputfield: - case Bytecodes::_fast_sputfield: - { - // We skip bytecode quickening for putfield instructions when - // the put_code written to the constant pool cache is zero. - // This is required so that every execution of this instruction - // calls out to InterpreterRuntime::resolve_get_put to do - // additional, required work. - assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); - assert(load_bc_into_bc_reg, "we use bc_reg as temp"); - __ get_cache_and_index_and_bytecode_at_bcp(bc_reg, temp_reg, temp_reg, byte_no, 1); - __ set(bc, bc_reg); - __ cmp_and_br_short(temp_reg, 0, Assembler::equal, Assembler::pn, L_patch_done); // don't patch - } - break; - default: - assert(byte_no == -1, "sanity"); - if (load_bc_into_bc_reg) { - __ set(bc, bc_reg); - } - } - - if (JvmtiExport::can_post_breakpoint()) { - Label L_fast_patch; - __ ldub(at_bcp(0), temp_reg); - __ cmp_and_br_short(temp_reg, Bytecodes::_breakpoint, Assembler::notEqual, Assembler::pt, L_fast_patch); - // perform the quickening, slowly, in the bowels of the breakpoint table - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), Lmethod, Lbcp, bc_reg); - __ ba_short(L_patch_done); - __ bind(L_fast_patch); - } - -#ifdef ASSERT - Bytecodes::Code orig_bytecode = Bytecodes::java_code(bc); - Label L_okay; - __ ldub(at_bcp(0), temp_reg); - __ cmp(temp_reg, orig_bytecode); - __ br(Assembler::equal, false, Assembler::pt, L_okay); - __ delayed()->cmp(temp_reg, bc_reg); - __ br(Assembler::equal, false, Assembler::pt, L_okay); - __ delayed()->nop(); - __ stop("patching the wrong bytecode"); - __ bind(L_okay); -#endif - - // patch bytecode - __ stb(bc_reg, at_bcp(0)); - __ bind(L_patch_done); -} - -//---------------------------------------------------------------------------------------------------- -// Individual instructions - -void TemplateTable::nop() { - transition(vtos, vtos); - // nothing to do -} - -void TemplateTable::shouldnotreachhere() { - transition(vtos, vtos); - __ stop("shouldnotreachhere bytecode"); -} - -void TemplateTable::aconst_null() { - transition(vtos, atos); - __ clr(Otos_i); -} - - -void TemplateTable::iconst(int value) { - transition(vtos, itos); - __ set(value, Otos_i); -} - - -void TemplateTable::lconst(int value) { - transition(vtos, ltos); - assert(value >= 0, "check this code"); - __ set(value, Otos_l); -} - - -void TemplateTable::fconst(int value) { - transition(vtos, ftos); - static float zero = 0.0, one = 1.0, two = 2.0; - float* p; - switch( value ) { - default: ShouldNotReachHere(); - case 0: p = &zero; break; - case 1: p = &one; break; - case 2: p = &two; break; - } - AddressLiteral a(p); - __ sethi(a, G3_scratch); - __ ldf(FloatRegisterImpl::S, G3_scratch, a.low10(), Ftos_f); -} - - -void TemplateTable::dconst(int value) { - transition(vtos, dtos); - static double zero = 0.0, one = 1.0; - double* p; - switch( value ) { - default: ShouldNotReachHere(); - case 0: p = &zero; break; - case 1: p = &one; break; - } - AddressLiteral a(p); - __ sethi(a, G3_scratch); - __ ldf(FloatRegisterImpl::D, G3_scratch, a.low10(), Ftos_d); -} - - -// %%%%% Should factore most snippet templates across platforms - -void TemplateTable::bipush() { - transition(vtos, itos); - __ ldsb( at_bcp(1), Otos_i ); -} - -void TemplateTable::sipush() { - transition(vtos, itos); - __ get_2_byte_integer_at_bcp(1, G3_scratch, Otos_i, InterpreterMacroAssembler::Signed); -} - -void TemplateTable::ldc(bool wide) { - transition(vtos, vtos); - Label call_ldc, notInt, isString, notString, notClass, notFloat, exit; - - if (wide) { - __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned); - } else { - __ ldub(Lbcp, 1, O1); - } - __ get_cpool_and_tags(O0, O2); - - const int base_offset = ConstantPool::header_size() * wordSize; - const int tags_offset = Array::base_offset_in_bytes(); - - // get type from tags - __ add(O2, tags_offset, O2); - __ ldub(O2, O1, O2); - - // unresolved class? If so, must resolve - __ cmp_and_brx_short(O2, JVM_CONSTANT_UnresolvedClass, Assembler::equal, Assembler::pt, call_ldc); - - // unresolved class in error state - __ cmp_and_brx_short(O2, JVM_CONSTANT_UnresolvedClassInError, Assembler::equal, Assembler::pn, call_ldc); - - __ cmp(O2, JVM_CONSTANT_Class); // need to call vm to get java mirror of the class - __ brx(Assembler::notEqual, true, Assembler::pt, notClass); - __ delayed()->add(O0, base_offset, O0); - - __ bind(call_ldc); - __ set(wide, O1); - call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), O1); - __ push(atos); - __ ba(exit); - __ delayed()->nop(); - - __ bind(notClass); - // __ add(O0, base_offset, O0); - __ sll(O1, LogBytesPerWord, O1); - __ cmp(O2, JVM_CONSTANT_Integer); - __ brx(Assembler::notEqual, true, Assembler::pt, notInt); - __ delayed()->cmp(O2, JVM_CONSTANT_String); - __ ld(O0, O1, Otos_i); - __ push(itos); - __ ba(exit); - __ delayed()->nop(); - - __ bind(notInt); - // __ cmp(O2, JVM_CONSTANT_String); - __ brx(Assembler::notEqual, true, Assembler::pt, notString); - __ delayed()->cmp(O2, JVM_CONSTANT_Float); - __ bind(isString); - __ stop("string should be rewritten to fast_aldc"); - __ ba(exit); - __ delayed()->nop(); - - __ bind(notString); - //__ cmp(O2, JVM_CONSTANT_Float); - __ brx(Assembler::notEqual, true, Assembler::pt, notFloat); - __ delayed()->nop(); - __ ldf(FloatRegisterImpl::S, O0, O1, Ftos_f); - __ push(ftos); - __ ba(exit); - __ delayed()->nop(); - - // assume the tag is for condy; if not, the VM runtime will tell us - __ bind(notFloat); - condy_helper(exit); - - __ bind(exit); -} - -// Fast path for caching oop constants. -// %%% We should use this to handle Class and String constants also. -// %%% It will simplify the ldc/primitive path considerably. -void TemplateTable::fast_aldc(bool wide) { - transition(vtos, atos); - - int index_size = wide ? sizeof(u2) : sizeof(u1); - Label resolved; - - // We are resolved if the resolved reference cache entry contains a - // non-null object (CallSite, etc.) - assert_different_registers(Otos_i, G3_scratch); - __ get_cache_index_at_bcp(Otos_i, G3_scratch, 1, index_size); // load index => G3_scratch - __ load_resolved_reference_at_index(Otos_i, G3_scratch, Lscratch); - __ tst(Otos_i); - __ br(Assembler::notEqual, false, Assembler::pt, resolved); - __ delayed()->set((int)bytecode(), O1); - - address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); - - // first time invocation - must resolve first - __ call_VM(Otos_i, entry, O1); - __ bind(resolved); - - { // Check for the null sentinel. - // If we just called the VM, it already did the mapping for us, - // but it's harmless to retry. - Label notNull; - __ set(ExternalAddress((address)Universe::the_null_sentinel_addr()), G3_scratch); - __ ld_ptr(G3_scratch, 0, G3_scratch); - __ cmp(G3_scratch, Otos_i); - __ br(Assembler::notEqual, true, Assembler::pt, notNull); - __ delayed()->nop(); - __ clr(Otos_i); // NULL object reference - __ bind(notNull); - } - - // Safe to call with 0 result - __ verify_oop(Otos_i); -} - -void TemplateTable::ldc2_w() { - transition(vtos, vtos); - Label notDouble, notLong, exit; - - __ get_2_byte_integer_at_bcp(1, G3_scratch, O1, InterpreterMacroAssembler::Unsigned); - __ get_cpool_and_tags(O0, O2); - - const int base_offset = ConstantPool::header_size() * wordSize; - const int tags_offset = Array::base_offset_in_bytes(); - // get type from tags - __ add(O2, tags_offset, O2); - __ ldub(O2, O1, O2); - - __ sll(O1, LogBytesPerWord, O1); - __ add(O0, O1, G3_scratch); - - __ cmp_and_brx_short(O2, JVM_CONSTANT_Double, Assembler::notEqual, Assembler::pt, notDouble); - // A double can be placed at word-aligned locations in the constant pool. - // Check out Conversions.java for an example. - // Also ConstantPool::header_size() is 20, which makes it very difficult - // to double-align double on the constant pool. SG, 11/7/97 - __ ldf(FloatRegisterImpl::D, G3_scratch, base_offset, Ftos_d); - __ push(dtos); - __ ba_short(exit); - - __ bind(notDouble); - __ cmp_and_brx_short(O2, JVM_CONSTANT_Long, Assembler::notEqual, Assembler::pt, notLong); - __ ldx(G3_scratch, base_offset, Otos_l); - __ push(ltos); - __ ba_short(exit); - - __ bind(notLong); - condy_helper(exit); - - __ bind(exit); -} - -void TemplateTable::condy_helper(Label& exit) { - Register Robj = Otos_i; - Register Roffset = G4_scratch; - Register Rflags = G1_scratch; - - address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); - - __ set((int)bytecode(), O1); - __ call_VM(Robj, entry, O1); - - // Get vm_result_2 has flags = (tos, off) using format CPCE::_flags - __ get_vm_result_2(G3_scratch); - - // Get offset - __ set((int)ConstantPoolCacheEntry::field_index_mask, Roffset); - __ and3(G3_scratch, Roffset, Roffset); - - // compute type - __ srl(G3_scratch, ConstantPoolCacheEntry::tos_state_shift, Rflags); - // Make sure we don't need to mask Rflags after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - - switch (bytecode()) { - case Bytecodes::_ldc: - case Bytecodes::_ldc_w: - { - // tos in (itos, ftos, stos, btos, ctos, ztos) - Label notInt, notFloat, notShort, notByte, notChar, notBool; - __ cmp(Rflags, itos); - __ br(Assembler::notEqual, false, Assembler::pt, notInt); - __ delayed()->cmp(Rflags, ftos); - // itos - __ ld(Robj, Roffset, Otos_i); - __ push(itos); - __ ba_short(exit); - - __ bind(notInt); - __ br(Assembler::notEqual, false, Assembler::pt, notFloat); - __ delayed()->cmp(Rflags, stos); - // ftos - __ ldf(FloatRegisterImpl::S, Robj, Roffset, Ftos_f); - __ push(ftos); - __ ba_short(exit); - - __ bind(notFloat); - __ br(Assembler::notEqual, false, Assembler::pt, notShort); - __ delayed()->cmp(Rflags, btos); - // stos - __ ldsh(Robj, Roffset, Otos_i); - __ push(itos); - __ ba_short(exit); - - __ bind(notShort); - __ br(Assembler::notEqual, false, Assembler::pt, notByte); - __ delayed()->cmp(Rflags, ctos); - // btos - __ ldsb(Robj, Roffset, Otos_i); - __ push(itos); - __ ba_short(exit); - - __ bind(notByte); - __ br(Assembler::notEqual, false, Assembler::pt, notChar); - __ delayed()->cmp(Rflags, ztos); - // ctos - __ lduh(Robj, Roffset, Otos_i); - __ push(itos); - __ ba_short(exit); - - __ bind(notChar); - __ br(Assembler::notEqual, false, Assembler::pt, notBool); - __ delayed()->nop(); - // ztos - __ ldsb(Robj, Roffset, Otos_i); - __ push(itos); - __ ba_short(exit); - - __ bind(notBool); - break; - } - - case Bytecodes::_ldc2_w: - { - Label notLong, notDouble; - __ cmp(Rflags, ltos); - __ br(Assembler::notEqual, false, Assembler::pt, notLong); - __ delayed()->cmp(Rflags, dtos); - // ltos - // load must be atomic - __ ld_long(Robj, Roffset, Otos_l); - __ push(ltos); - __ ba_short(exit); - - __ bind(notLong); - __ br(Assembler::notEqual, false, Assembler::pt, notDouble); - __ delayed()->nop(); - // dtos - __ ldf(FloatRegisterImpl::D, Robj, Roffset, Ftos_d); - __ push(dtos); - __ ba_short(exit); - - __ bind(notDouble); - break; - } - - default: - ShouldNotReachHere(); - } - - __ stop("bad ldc/condy"); - - __ bind(exit); -} - -void TemplateTable::locals_index(Register reg, int offset) { - __ ldub( at_bcp(offset), reg ); -} - -void TemplateTable::locals_index_wide(Register reg) { - // offset is 2, not 1, because Lbcp points to wide prefix code - __ get_2_byte_integer_at_bcp(2, G4_scratch, reg, InterpreterMacroAssembler::Unsigned); -} - -void TemplateTable::iload() { - iload_internal(); -} - -void TemplateTable::nofast_iload() { - iload_internal(may_not_rewrite); -} - -void TemplateTable::iload_internal(RewriteControl rc) { - transition(vtos, itos); - // Rewrite iload,iload pair into fast_iload2 - // iload,caload pair into fast_icaload - if (RewriteFrequentPairs && rc == may_rewrite) { - Label rewrite, done; - - // get next byte - __ ldub(at_bcp(Bytecodes::length_for(Bytecodes::_iload)), G3_scratch); - - // if _iload, wait to rewrite to iload2. We only want to rewrite the - // last two iloads in a pair. Comparing against fast_iload means that - // the next bytecode is neither an iload or a caload, and therefore - // an iload pair. - __ cmp_and_br_short(G3_scratch, (int)Bytecodes::_iload, Assembler::equal, Assembler::pn, done); - - __ cmp(G3_scratch, (int)Bytecodes::_fast_iload); - __ br(Assembler::equal, false, Assembler::pn, rewrite); - __ delayed()->set(Bytecodes::_fast_iload2, G4_scratch); - - __ cmp(G3_scratch, (int)Bytecodes::_caload); - __ br(Assembler::equal, false, Assembler::pn, rewrite); - __ delayed()->set(Bytecodes::_fast_icaload, G4_scratch); - - __ set(Bytecodes::_fast_iload, G4_scratch); // don't check again - // rewrite - // G4_scratch: fast bytecode - __ bind(rewrite); - patch_bytecode(Bytecodes::_iload, G4_scratch, G3_scratch, false); - __ bind(done); - } - - // Get the local value into tos - locals_index(G3_scratch); - __ access_local_int( G3_scratch, Otos_i ); -} - -void TemplateTable::fast_iload2() { - transition(vtos, itos); - locals_index(G3_scratch); - __ access_local_int( G3_scratch, Otos_i ); - __ push_i(); - locals_index(G3_scratch, 3); // get next bytecode's local index. - __ access_local_int( G3_scratch, Otos_i ); -} - -void TemplateTable::fast_iload() { - transition(vtos, itos); - locals_index(G3_scratch); - __ access_local_int( G3_scratch, Otos_i ); -} - -void TemplateTable::lload() { - transition(vtos, ltos); - locals_index(G3_scratch); - __ access_local_long( G3_scratch, Otos_l ); -} - - -void TemplateTable::fload() { - transition(vtos, ftos); - locals_index(G3_scratch); - __ access_local_float( G3_scratch, Ftos_f ); -} - - -void TemplateTable::dload() { - transition(vtos, dtos); - locals_index(G3_scratch); - __ access_local_double( G3_scratch, Ftos_d ); -} - - -void TemplateTable::aload() { - transition(vtos, atos); - locals_index(G3_scratch); - __ access_local_ptr( G3_scratch, Otos_i); -} - - -void TemplateTable::wide_iload() { - transition(vtos, itos); - locals_index_wide(G3_scratch); - __ access_local_int( G3_scratch, Otos_i ); -} - - -void TemplateTable::wide_lload() { - transition(vtos, ltos); - locals_index_wide(G3_scratch); - __ access_local_long( G3_scratch, Otos_l ); -} - - -void TemplateTable::wide_fload() { - transition(vtos, ftos); - locals_index_wide(G3_scratch); - __ access_local_float( G3_scratch, Ftos_f ); -} - - -void TemplateTable::wide_dload() { - transition(vtos, dtos); - locals_index_wide(G3_scratch); - __ access_local_double( G3_scratch, Ftos_d ); -} - - -void TemplateTable::wide_aload() { - transition(vtos, atos); - locals_index_wide(G3_scratch); - __ access_local_ptr( G3_scratch, Otos_i ); - __ verify_oop(Otos_i); -} - - -void TemplateTable::iaload() { - transition(itos, itos); - // Otos_i: index - // tos: array - __ index_check(O2, Otos_i, LogBytesPerInt, G3_scratch, O3); - __ ld(O3, arrayOopDesc::base_offset_in_bytes(T_INT), Otos_i); -} - - -void TemplateTable::laload() { - transition(itos, ltos); - // Otos_i: index - // O2: array - __ index_check(O2, Otos_i, LogBytesPerLong, G3_scratch, O3); - __ ld_long(O3, arrayOopDesc::base_offset_in_bytes(T_LONG), Otos_l); -} - - -void TemplateTable::faload() { - transition(itos, ftos); - // Otos_i: index - // O2: array - __ index_check(O2, Otos_i, LogBytesPerInt, G3_scratch, O3); - __ ldf(FloatRegisterImpl::S, O3, arrayOopDesc::base_offset_in_bytes(T_FLOAT), Ftos_f); -} - - -void TemplateTable::daload() { - transition(itos, dtos); - // Otos_i: index - // O2: array - __ index_check(O2, Otos_i, LogBytesPerLong, G3_scratch, O3); - __ ldf(FloatRegisterImpl::D, O3, arrayOopDesc::base_offset_in_bytes(T_DOUBLE), Ftos_d); -} - - -void TemplateTable::aaload() { - transition(itos, atos); - // Otos_i: index - // tos: array - __ index_check(O2, Otos_i, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O3); - do_oop_load(_masm, - O3, - noreg, - arrayOopDesc::base_offset_in_bytes(T_OBJECT), - Otos_i, - G3_scratch, - IS_ARRAY); - __ verify_oop(Otos_i); -} - - -void TemplateTable::baload() { - transition(itos, itos); - // Otos_i: index - // tos: array - __ index_check(O2, Otos_i, 0, G3_scratch, O3); - __ ldsb(O3, arrayOopDesc::base_offset_in_bytes(T_BYTE), Otos_i); -} - - -void TemplateTable::caload() { - transition(itos, itos); - // Otos_i: index - // tos: array - __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3); - __ lduh(O3, arrayOopDesc::base_offset_in_bytes(T_CHAR), Otos_i); -} - -void TemplateTable::fast_icaload() { - transition(vtos, itos); - // Otos_i: index - // tos: array - locals_index(G3_scratch); - __ access_local_int( G3_scratch, Otos_i ); - __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3); - __ lduh(O3, arrayOopDesc::base_offset_in_bytes(T_CHAR), Otos_i); -} - - -void TemplateTable::saload() { - transition(itos, itos); - // Otos_i: index - // tos: array - __ index_check(O2, Otos_i, LogBytesPerShort, G3_scratch, O3); - __ ldsh(O3, arrayOopDesc::base_offset_in_bytes(T_SHORT), Otos_i); -} - - -void TemplateTable::iload(int n) { - transition(vtos, itos); - __ ld( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i ); -} - - -void TemplateTable::lload(int n) { - transition(vtos, ltos); - assert(n+1 < Argument::n_register_parameters, "would need more code"); - __ load_unaligned_long(Llocals, Interpreter::local_offset_in_bytes(n+1), Otos_l); -} - - -void TemplateTable::fload(int n) { - transition(vtos, ftos); - assert(n < Argument::n_register_parameters, "would need more code"); - __ ldf( FloatRegisterImpl::S, Llocals, Interpreter::local_offset_in_bytes(n), Ftos_f ); -} - - -void TemplateTable::dload(int n) { - transition(vtos, dtos); - FloatRegister dst = Ftos_d; - __ load_unaligned_double(Llocals, Interpreter::local_offset_in_bytes(n+1), dst); -} - - -void TemplateTable::aload(int n) { - transition(vtos, atos); - __ ld_ptr( Llocals, Interpreter::local_offset_in_bytes(n), Otos_i ); -} - -void TemplateTable::aload_0() { - aload_0_internal(); -} - -void TemplateTable::nofast_aload_0() { - aload_0_internal(may_not_rewrite); -} - -void TemplateTable::aload_0_internal(RewriteControl rc) { - transition(vtos, atos); - - // According to bytecode histograms, the pairs: - // - // _aload_0, _fast_igetfield (itos) - // _aload_0, _fast_agetfield (atos) - // _aload_0, _fast_fgetfield (ftos) - // - // occur frequently. If RewriteFrequentPairs is set, the (slow) _aload_0 - // bytecode checks the next bytecode and then rewrites the current - // bytecode into a pair bytecode; otherwise it rewrites the current - // bytecode into _fast_aload_0 that doesn't do the pair check anymore. - // - if (RewriteFrequentPairs && rc == may_rewrite) { - Label rewrite, done; - - // get next byte - __ ldub(at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)), G3_scratch); - - // if _getfield then wait with rewrite - __ cmp_and_br_short(G3_scratch, (int)Bytecodes::_getfield, Assembler::equal, Assembler::pn, done); - - // if _igetfield then rewrite to _fast_iaccess_0 - assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); - __ cmp(G3_scratch, (int)Bytecodes::_fast_igetfield); - __ br(Assembler::equal, false, Assembler::pn, rewrite); - __ delayed()->set(Bytecodes::_fast_iaccess_0, G4_scratch); - - // if _agetfield then rewrite to _fast_aaccess_0 - assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); - __ cmp(G3_scratch, (int)Bytecodes::_fast_agetfield); - __ br(Assembler::equal, false, Assembler::pn, rewrite); - __ delayed()->set(Bytecodes::_fast_aaccess_0, G4_scratch); - - // if _fgetfield then rewrite to _fast_faccess_0 - assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); - __ cmp(G3_scratch, (int)Bytecodes::_fast_fgetfield); - __ br(Assembler::equal, false, Assembler::pn, rewrite); - __ delayed()->set(Bytecodes::_fast_faccess_0, G4_scratch); - - // else rewrite to _fast_aload0 - assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "adjust fast bytecode def"); - __ set(Bytecodes::_fast_aload_0, G4_scratch); - - // rewrite - // G4_scratch: fast bytecode - __ bind(rewrite); - patch_bytecode(Bytecodes::_aload_0, G4_scratch, G3_scratch, false); - __ bind(done); - } - - // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop). - aload(0); -} - -void TemplateTable::istore() { - transition(itos, vtos); - locals_index(G3_scratch); - __ store_local_int( G3_scratch, Otos_i ); -} - - -void TemplateTable::lstore() { - transition(ltos, vtos); - locals_index(G3_scratch); - __ store_local_long( G3_scratch, Otos_l ); -} - - -void TemplateTable::fstore() { - transition(ftos, vtos); - locals_index(G3_scratch); - __ store_local_float( G3_scratch, Ftos_f ); -} - - -void TemplateTable::dstore() { - transition(dtos, vtos); - locals_index(G3_scratch); - __ store_local_double( G3_scratch, Ftos_d ); -} - - -void TemplateTable::astore() { - transition(vtos, vtos); - __ load_ptr(0, Otos_i); - __ inc(Lesp, Interpreter::stackElementSize); - __ verify_oop_or_return_address(Otos_i, G3_scratch); - locals_index(G3_scratch); - __ store_local_ptr(G3_scratch, Otos_i); -} - - -void TemplateTable::wide_istore() { - transition(vtos, vtos); - __ pop_i(); - locals_index_wide(G3_scratch); - __ store_local_int( G3_scratch, Otos_i ); -} - - -void TemplateTable::wide_lstore() { - transition(vtos, vtos); - __ pop_l(); - locals_index_wide(G3_scratch); - __ store_local_long( G3_scratch, Otos_l ); -} - - -void TemplateTable::wide_fstore() { - transition(vtos, vtos); - __ pop_f(); - locals_index_wide(G3_scratch); - __ store_local_float( G3_scratch, Ftos_f ); -} - - -void TemplateTable::wide_dstore() { - transition(vtos, vtos); - __ pop_d(); - locals_index_wide(G3_scratch); - __ store_local_double( G3_scratch, Ftos_d ); -} - - -void TemplateTable::wide_astore() { - transition(vtos, vtos); - __ load_ptr(0, Otos_i); - __ inc(Lesp, Interpreter::stackElementSize); - __ verify_oop_or_return_address(Otos_i, G3_scratch); - locals_index_wide(G3_scratch); - __ store_local_ptr(G3_scratch, Otos_i); -} - - -void TemplateTable::iastore() { - transition(itos, vtos); - __ pop_i(O2); // index - // Otos_i: val - // O3: array - __ index_check(O3, O2, LogBytesPerInt, G3_scratch, O2); - __ st(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_INT)); -} - - -void TemplateTable::lastore() { - transition(ltos, vtos); - __ pop_i(O2); // index - // Otos_l: val - // O3: array - __ index_check(O3, O2, LogBytesPerLong, G3_scratch, O2); - __ st_long(Otos_l, O2, arrayOopDesc::base_offset_in_bytes(T_LONG)); -} - - -void TemplateTable::fastore() { - transition(ftos, vtos); - __ pop_i(O2); // index - // Ftos_f: val - // O3: array - __ index_check(O3, O2, LogBytesPerInt, G3_scratch, O2); - __ stf(FloatRegisterImpl::S, Ftos_f, O2, arrayOopDesc::base_offset_in_bytes(T_FLOAT)); -} - - -void TemplateTable::dastore() { - transition(dtos, vtos); - __ pop_i(O2); // index - // Fos_d: val - // O3: array - __ index_check(O3, O2, LogBytesPerLong, G3_scratch, O2); - __ stf(FloatRegisterImpl::D, Ftos_d, O2, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)); -} - - -void TemplateTable::aastore() { - Label store_ok, is_null, done; - transition(vtos, vtos); - __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i); - __ ld(Lesp, Interpreter::expr_offset_in_bytes(1), O2); // get index - __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(2), O3); // get array - // Otos_i: val - // O2: index - // O3: array - __ verify_oop(Otos_i); - __ index_check_without_pop(O3, O2, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O1); - - // do array store check - check for NULL value first - __ br_null_short( Otos_i, Assembler::pn, is_null ); - - __ load_klass(O3, O4); // get array klass - __ load_klass(Otos_i, O5); // get value klass - - // do fast instanceof cache test - - __ ld_ptr(O4, in_bytes(ObjArrayKlass::element_klass_offset()), O4); - - assert(Otos_i == O0, "just checking"); - - // Otos_i: value - // O1: addr - offset - // O2: index - // O3: array - // O4: array element klass - // O5: value klass - - // Address element(O1, 0, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); - - // Generate a fast subtype check. Branch to store_ok if no - // failure. Throw if failure. - __ gen_subtype_check( O5, O4, G3_scratch, G4_scratch, G1_scratch, store_ok ); - - // Not a subtype; so must throw exception - __ throw_if_not_x( Assembler::never, Interpreter::_throw_ArrayStoreException_entry, G3_scratch ); - - // Store is OK. - __ bind(store_ok); - do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i, G3_scratch, IS_ARRAY); - - __ ba(done); - __ delayed()->inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value) - - __ bind(is_null); - do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), G0, G4_scratch, IS_ARRAY); - - __ profile_null_seen(G3_scratch); - __ inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value) - __ bind(done); -} - - -void TemplateTable::bastore() { - transition(itos, vtos); - __ pop_i(O2); // index - // Otos_i: val - // O2: index - // O3: array - __ index_check(O3, O2, 0, G3_scratch, O2); - // Need to check whether array is boolean or byte - // since both types share the bastore bytecode. - __ load_klass(O3, G4_scratch); - __ ld(G4_scratch, in_bytes(Klass::layout_helper_offset()), G4_scratch); - __ set(Klass::layout_helper_boolean_diffbit(), G3_scratch); - __ andcc(G3_scratch, G4_scratch, G0); - Label L_skip; - __ br(Assembler::zero, false, Assembler::pn, L_skip); - __ delayed()->nop(); - __ and3(Otos_i, 1, Otos_i); // if it is a T_BOOLEAN array, mask the stored value to 0/1 - __ bind(L_skip); - __ stb(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_BYTE)); -} - - -void TemplateTable::castore() { - transition(itos, vtos); - __ pop_i(O2); // index - // Otos_i: val - // O3: array - __ index_check(O3, O2, LogBytesPerShort, G3_scratch, O2); - __ sth(Otos_i, O2, arrayOopDesc::base_offset_in_bytes(T_CHAR)); -} - - -void TemplateTable::sastore() { - // %%%%% Factor across platform - castore(); -} - - -void TemplateTable::istore(int n) { - transition(itos, vtos); - __ st(Otos_i, Llocals, Interpreter::local_offset_in_bytes(n)); -} - - -void TemplateTable::lstore(int n) { - transition(ltos, vtos); - assert(n+1 < Argument::n_register_parameters, "only handle register cases"); - __ store_unaligned_long(Otos_l, Llocals, Interpreter::local_offset_in_bytes(n+1)); - -} - - -void TemplateTable::fstore(int n) { - transition(ftos, vtos); - assert(n < Argument::n_register_parameters, "only handle register cases"); - __ stf(FloatRegisterImpl::S, Ftos_f, Llocals, Interpreter::local_offset_in_bytes(n)); -} - - -void TemplateTable::dstore(int n) { - transition(dtos, vtos); - FloatRegister src = Ftos_d; - __ store_unaligned_double(src, Llocals, Interpreter::local_offset_in_bytes(n+1)); -} - - -void TemplateTable::astore(int n) { - transition(vtos, vtos); - __ load_ptr(0, Otos_i); - __ inc(Lesp, Interpreter::stackElementSize); - __ verify_oop_or_return_address(Otos_i, G3_scratch); - __ store_local_ptr(n, Otos_i); -} - - -void TemplateTable::pop() { - transition(vtos, vtos); - __ inc(Lesp, Interpreter::stackElementSize); -} - - -void TemplateTable::pop2() { - transition(vtos, vtos); - __ inc(Lesp, 2 * Interpreter::stackElementSize); -} - - -void TemplateTable::dup() { - transition(vtos, vtos); - // stack: ..., a - // load a and tag - __ load_ptr(0, Otos_i); - __ push_ptr(Otos_i); - // stack: ..., a, a -} - - -void TemplateTable::dup_x1() { - transition(vtos, vtos); - // stack: ..., a, b - __ load_ptr( 1, G3_scratch); // get a - __ load_ptr( 0, Otos_l1); // get b - __ store_ptr(1, Otos_l1); // put b - __ store_ptr(0, G3_scratch); // put a - like swap - __ push_ptr(Otos_l1); // push b - // stack: ..., b, a, b -} - - -void TemplateTable::dup_x2() { - transition(vtos, vtos); - // stack: ..., a, b, c - // get c and push on stack, reuse registers - __ load_ptr( 0, G3_scratch); // get c - __ push_ptr(G3_scratch); // push c with tag - // stack: ..., a, b, c, c (c in reg) (Lesp - 4) - // (stack offsets n+1 now) - __ load_ptr( 3, Otos_l1); // get a - __ store_ptr(3, G3_scratch); // put c at 3 - // stack: ..., c, b, c, c (a in reg) - __ load_ptr( 2, G3_scratch); // get b - __ store_ptr(2, Otos_l1); // put a at 2 - // stack: ..., c, a, c, c (b in reg) - __ store_ptr(1, G3_scratch); // put b at 1 - // stack: ..., c, a, b, c -} - - -void TemplateTable::dup2() { - transition(vtos, vtos); - __ load_ptr(1, G3_scratch); // get a - __ load_ptr(0, Otos_l1); // get b - __ push_ptr(G3_scratch); // push a - __ push_ptr(Otos_l1); // push b - // stack: ..., a, b, a, b -} - - -void TemplateTable::dup2_x1() { - transition(vtos, vtos); - // stack: ..., a, b, c - __ load_ptr( 1, Lscratch); // get b - __ load_ptr( 2, Otos_l1); // get a - __ store_ptr(2, Lscratch); // put b at a - // stack: ..., b, b, c - __ load_ptr( 0, G3_scratch); // get c - __ store_ptr(1, G3_scratch); // put c at b - // stack: ..., b, c, c - __ store_ptr(0, Otos_l1); // put a at c - // stack: ..., b, c, a - __ push_ptr(Lscratch); // push b - __ push_ptr(G3_scratch); // push c - // stack: ..., b, c, a, b, c -} - - -// The spec says that these types can be a mixture of category 1 (1 word) -// types and/or category 2 types (long and doubles) -void TemplateTable::dup2_x2() { - transition(vtos, vtos); - // stack: ..., a, b, c, d - __ load_ptr( 1, Lscratch); // get c - __ load_ptr( 3, Otos_l1); // get a - __ store_ptr(3, Lscratch); // put c at 3 - __ store_ptr(1, Otos_l1); // put a at 1 - // stack: ..., c, b, a, d - __ load_ptr( 2, G3_scratch); // get b - __ load_ptr( 0, Otos_l1); // get d - __ store_ptr(0, G3_scratch); // put b at 0 - __ store_ptr(2, Otos_l1); // put d at 2 - // stack: ..., c, d, a, b - __ push_ptr(Lscratch); // push c - __ push_ptr(Otos_l1); // push d - // stack: ..., c, d, a, b, c, d -} - - -void TemplateTable::swap() { - transition(vtos, vtos); - // stack: ..., a, b - __ load_ptr( 1, G3_scratch); // get a - __ load_ptr( 0, Otos_l1); // get b - __ store_ptr(0, G3_scratch); // put b - __ store_ptr(1, Otos_l1); // put a - // stack: ..., b, a -} - - -void TemplateTable::iop2(Operation op) { - transition(itos, itos); - __ pop_i(O1); - switch (op) { - case add: __ add(O1, Otos_i, Otos_i); break; - case sub: __ sub(O1, Otos_i, Otos_i); break; - // %%%%% Mul may not exist: better to call .mul? - case mul: __ smul(O1, Otos_i, Otos_i); break; - case _and: __ and3(O1, Otos_i, Otos_i); break; - case _or: __ or3(O1, Otos_i, Otos_i); break; - case _xor: __ xor3(O1, Otos_i, Otos_i); break; - case shl: __ sll(O1, Otos_i, Otos_i); break; - case shr: __ sra(O1, Otos_i, Otos_i); break; - case ushr: __ srl(O1, Otos_i, Otos_i); break; - default: ShouldNotReachHere(); - } -} - - -void TemplateTable::lop2(Operation op) { - transition(ltos, ltos); - __ pop_l(O2); - switch (op) { - case add: __ add(O2, Otos_l, Otos_l); break; - case sub: __ sub(O2, Otos_l, Otos_l); break; - case _and: __ and3(O2, Otos_l, Otos_l); break; - case _or: __ or3(O2, Otos_l, Otos_l); break; - case _xor: __ xor3(O2, Otos_l, Otos_l); break; - default: ShouldNotReachHere(); - } -} - - -void TemplateTable::idiv() { - // %%%%% Later: ForSPARC/V7 call .sdiv library routine, - // %%%%% Use ldsw...sdivx on pure V9 ABI. 64 bit safe. - - transition(itos, itos); - __ pop_i(O1); // get 1st op - - // Y contains upper 32 bits of result, set it to 0 or all ones - __ wry(G0); - __ mov(~0, G3_scratch); - - __ tst(O1); - Label neg; - __ br(Assembler::negative, true, Assembler::pn, neg); - __ delayed()->wry(G3_scratch); - __ bind(neg); - - Label ok; - __ tst(Otos_i); - __ throw_if_not_icc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch ); - - const int min_int = 0x80000000; - Label regular; - __ cmp(Otos_i, -1); - __ br(Assembler::notEqual, false, Assembler::pt, regular); - // Don't put set in delay slot - // Set will turn into multiple instructions in 64 bit mode - __ delayed()->nop(); - __ set(min_int, G4_scratch); - Label done; - __ cmp(O1, G4_scratch); - __ br(Assembler::equal, true, Assembler::pt, done); - __ delayed()->mov(O1, Otos_i); // (mov only executed if branch taken) - - __ bind(regular); - __ sdiv(O1, Otos_i, Otos_i); // note: irem uses O1 after this instruction! - __ bind(done); -} - - -void TemplateTable::irem() { - transition(itos, itos); - __ mov(Otos_i, O2); // save divisor - idiv(); // %%%% Hack: exploits fact that idiv leaves dividend in O1 - __ smul(Otos_i, O2, Otos_i); - __ sub(O1, Otos_i, Otos_i); -} - - -void TemplateTable::lmul() { - transition(ltos, ltos); - __ pop_l(O2); - __ mulx(Otos_l, O2, Otos_l); - -} - - -void TemplateTable::ldiv() { - transition(ltos, ltos); - - // check for zero - __ pop_l(O2); - __ tst(Otos_l); - __ throw_if_not_xcc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch); - __ sdivx(O2, Otos_l, Otos_l); -} - - -void TemplateTable::lrem() { - transition(ltos, ltos); - - // check for zero - __ pop_l(O2); - __ tst(Otos_l); - __ throw_if_not_xcc( Assembler::notZero, Interpreter::_throw_ArithmeticException_entry, G3_scratch); - __ sdivx(O2, Otos_l, Otos_l2); - __ mulx (Otos_l2, Otos_l, Otos_l2); - __ sub (O2, Otos_l2, Otos_l); -} - - -void TemplateTable::lshl() { - transition(itos, ltos); // %%%% could optimize, fill delay slot or opt for ultra - - __ pop_l(O2); // shift value in O2, O3 - __ sllx(O2, Otos_i, Otos_l); -} - - -void TemplateTable::lshr() { - transition(itos, ltos); // %%%% see lshl comment - - __ pop_l(O2); // shift value in O2, O3 - __ srax(O2, Otos_i, Otos_l); -} - - - -void TemplateTable::lushr() { - transition(itos, ltos); // %%%% see lshl comment - - __ pop_l(O2); // shift value in O2, O3 - __ srlx(O2, Otos_i, Otos_l); -} - - -void TemplateTable::fop2(Operation op) { - transition(ftos, ftos); - switch (op) { - case add: __ pop_f(F4); __ fadd(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; - case sub: __ pop_f(F4); __ fsub(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; - case mul: __ pop_f(F4); __ fmul(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; - case div: __ pop_f(F4); __ fdiv(FloatRegisterImpl::S, F4, Ftos_f, Ftos_f); break; - case rem: - assert(Ftos_f == F0, "just checking"); - // LP64 calling conventions use F1, F3 for passing 2 floats - __ pop_f(F1); - __ fmov(FloatRegisterImpl::S, Ftos_f, F3); - __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::frem)); - assert( Ftos_f == F0, "fix this code" ); - break; - - default: ShouldNotReachHere(); - } -} - - -void TemplateTable::dop2(Operation op) { - transition(dtos, dtos); - switch (op) { - case add: __ pop_d(F4); __ fadd(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; - case sub: __ pop_d(F4); __ fsub(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; - case mul: __ pop_d(F4); __ fmul(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; - case div: __ pop_d(F4); __ fdiv(FloatRegisterImpl::D, F4, Ftos_d, Ftos_d); break; - case rem: - // Pass arguments in D0, D2 - __ fmov(FloatRegisterImpl::D, Ftos_f, F2 ); - __ pop_d( F0 ); - __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::drem)); - assert( Ftos_d == F0, "fix this code" ); - break; - - default: ShouldNotReachHere(); - } -} - - -void TemplateTable::ineg() { - transition(itos, itos); - __ neg(Otos_i); -} - - -void TemplateTable::lneg() { - transition(ltos, ltos); - __ sub(G0, Otos_l, Otos_l); -} - - -void TemplateTable::fneg() { - transition(ftos, ftos); - __ fneg(FloatRegisterImpl::S, Ftos_f, Ftos_f); -} - - -void TemplateTable::dneg() { - transition(dtos, dtos); - __ fneg(FloatRegisterImpl::D, Ftos_f, Ftos_f); -} - - -void TemplateTable::iinc() { - transition(vtos, vtos); - locals_index(G3_scratch); - __ ldsb(Lbcp, 2, O2); // load constant - __ access_local_int(G3_scratch, Otos_i); - __ add(Otos_i, O2, Otos_i); - __ st(Otos_i, G3_scratch, 0); // access_local_int puts E.A. in G3_scratch -} - - -void TemplateTable::wide_iinc() { - transition(vtos, vtos); - locals_index_wide(G3_scratch); - __ get_2_byte_integer_at_bcp( 4, O2, O3, InterpreterMacroAssembler::Signed); - __ access_local_int(G3_scratch, Otos_i); - __ add(Otos_i, O3, Otos_i); - __ st(Otos_i, G3_scratch, 0); // access_local_int puts E.A. in G3_scratch -} - - -void TemplateTable::convert() { -// %%%%% Factor this first part accross platforms - #ifdef ASSERT - TosState tos_in = ilgl; - TosState tos_out = ilgl; - switch (bytecode()) { - case Bytecodes::_i2l: // fall through - case Bytecodes::_i2f: // fall through - case Bytecodes::_i2d: // fall through - case Bytecodes::_i2b: // fall through - case Bytecodes::_i2c: // fall through - case Bytecodes::_i2s: tos_in = itos; break; - case Bytecodes::_l2i: // fall through - case Bytecodes::_l2f: // fall through - case Bytecodes::_l2d: tos_in = ltos; break; - case Bytecodes::_f2i: // fall through - case Bytecodes::_f2l: // fall through - case Bytecodes::_f2d: tos_in = ftos; break; - case Bytecodes::_d2i: // fall through - case Bytecodes::_d2l: // fall through - case Bytecodes::_d2f: tos_in = dtos; break; - default : ShouldNotReachHere(); - } - switch (bytecode()) { - case Bytecodes::_l2i: // fall through - case Bytecodes::_f2i: // fall through - case Bytecodes::_d2i: // fall through - case Bytecodes::_i2b: // fall through - case Bytecodes::_i2c: // fall through - case Bytecodes::_i2s: tos_out = itos; break; - case Bytecodes::_i2l: // fall through - case Bytecodes::_f2l: // fall through - case Bytecodes::_d2l: tos_out = ltos; break; - case Bytecodes::_i2f: // fall through - case Bytecodes::_l2f: // fall through - case Bytecodes::_d2f: tos_out = ftos; break; - case Bytecodes::_i2d: // fall through - case Bytecodes::_l2d: // fall through - case Bytecodes::_f2d: tos_out = dtos; break; - default : ShouldNotReachHere(); - } - transition(tos_in, tos_out); - #endif - - - // Conversion - Label done; - switch (bytecode()) { - case Bytecodes::_i2l: - // Sign extend the 32 bits - __ sra ( Otos_i, 0, Otos_l ); - break; - - case Bytecodes::_i2f: - __ st(Otos_i, __ d_tmp ); - __ ldf(FloatRegisterImpl::S, __ d_tmp, F0); - __ fitof(FloatRegisterImpl::S, F0, Ftos_f); - break; - - case Bytecodes::_i2d: - __ st(Otos_i, __ d_tmp); - __ ldf(FloatRegisterImpl::S, __ d_tmp, F0); - __ fitof(FloatRegisterImpl::D, F0, Ftos_f); - break; - - case Bytecodes::_i2b: - __ sll(Otos_i, 24, Otos_i); - __ sra(Otos_i, 24, Otos_i); - break; - - case Bytecodes::_i2c: - __ sll(Otos_i, 16, Otos_i); - __ srl(Otos_i, 16, Otos_i); - break; - - case Bytecodes::_i2s: - __ sll(Otos_i, 16, Otos_i); - __ sra(Otos_i, 16, Otos_i); - break; - - case Bytecodes::_l2i: - // Sign-extend into the high 32 bits - __ sra(Otos_l, 0, Otos_i); - break; - - case Bytecodes::_l2f: - case Bytecodes::_l2d: - __ st_long(Otos_l, __ d_tmp); - __ ldf(FloatRegisterImpl::D, __ d_tmp, Ftos_d); - - if (bytecode() == Bytecodes::_l2f) { - __ fxtof(FloatRegisterImpl::S, Ftos_d, Ftos_f); - } else { - __ fxtof(FloatRegisterImpl::D, Ftos_d, Ftos_d); - } - break; - - case Bytecodes::_f2i: { - Label isNaN; - // result must be 0 if value is NaN; test by comparing value to itself - __ fcmp(FloatRegisterImpl::S, Assembler::fcc0, Ftos_f, Ftos_f); - __ fb(Assembler::f_unordered, true, Assembler::pn, isNaN); - __ delayed()->clr(Otos_i); // NaN - __ ftoi(FloatRegisterImpl::S, Ftos_f, F30); - __ stf(FloatRegisterImpl::S, F30, __ d_tmp); - __ ld(__ d_tmp, Otos_i); - __ bind(isNaN); - } - break; - - case Bytecodes::_f2l: - // must uncache tos - __ push_f(); - __ pop_f(F1); - __ call_VM_leaf(Lscratch, CAST_FROM_FN_PTR(address, SharedRuntime::f2l)); - break; - - case Bytecodes::_f2d: - __ ftof( FloatRegisterImpl::S, FloatRegisterImpl::D, Ftos_f, Ftos_f); - break; - - case Bytecodes::_d2i: - case Bytecodes::_d2l: - // must uncache tos - __ push_d(); - // LP64 calling conventions pass first double arg in D0 - __ pop_d( Ftos_d ); - __ call_VM_leaf(Lscratch, - bytecode() == Bytecodes::_d2i - ? CAST_FROM_FN_PTR(address, SharedRuntime::d2i) - : CAST_FROM_FN_PTR(address, SharedRuntime::d2l)); - break; - - case Bytecodes::_d2f: - __ ftof( FloatRegisterImpl::D, FloatRegisterImpl::S, Ftos_d, Ftos_f); - break; - - default: ShouldNotReachHere(); - } - __ bind(done); -} - - -void TemplateTable::lcmp() { - transition(ltos, itos); - - __ pop_l(O1); // pop off value 1, value 2 is in O0 - __ lcmp( O1, Otos_l, Otos_i ); -} - - -void TemplateTable::float_cmp(bool is_float, int unordered_result) { - - if (is_float) __ pop_f(F2); - else __ pop_d(F2); - - assert(Ftos_f == F0 && Ftos_d == F0, "alias checking:"); - - __ float_cmp( is_float, unordered_result, F2, F0, Otos_i ); -} - -void TemplateTable::branch(bool is_jsr, bool is_wide) { - // Note: on SPARC, we use InterpreterMacroAssembler::if_cmp also. - __ verify_thread(); - - const Register O2_bumped_count = O2; - __ profile_taken_branch(G3_scratch, O2_bumped_count); - - // get (wide) offset to O1_disp - const Register O1_disp = O1; - if (is_wide) __ get_4_byte_integer_at_bcp( 1, G4_scratch, O1_disp, InterpreterMacroAssembler::set_CC); - else __ get_2_byte_integer_at_bcp( 1, G4_scratch, O1_disp, InterpreterMacroAssembler::Signed, InterpreterMacroAssembler::set_CC); - - // Handle all the JSR stuff here, then exit. - // It's much shorter and cleaner than intermingling with the - // non-JSR normal-branch stuff occurring below. - if( is_jsr ) { - // compute return address as bci in Otos_i - __ ld_ptr(Lmethod, Method::const_offset(), G3_scratch); - __ sub(Lbcp, G3_scratch, G3_scratch); - __ sub(G3_scratch, in_bytes(ConstMethod::codes_offset()) - (is_wide ? 5 : 3), Otos_i); - - // Bump Lbcp to target of JSR - __ add(Lbcp, O1_disp, Lbcp); - // Push returnAddress for "ret" on stack - __ push_ptr(Otos_i); - // And away we go! - __ dispatch_next(vtos, 0, true); - return; - } - - // Normal (non-jsr) branch handling - - // Save the current Lbcp - const Register l_cur_bcp = Lscratch; - __ mov( Lbcp, l_cur_bcp ); - - bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; - if ( increment_invocation_counter_for_backward_branches ) { - Label Lforward; - // check branch direction - __ br( Assembler::positive, false, Assembler::pn, Lforward ); - // Bump bytecode pointer by displacement (take the branch) - __ delayed()->add( O1_disp, Lbcp, Lbcp ); // add to bc addr - - const Register G3_method_counters = G3_scratch; - __ get_method_counters(Lmethod, G3_method_counters, Lforward); - - if (TieredCompilation) { - Label Lno_mdo, Loverflow; - int increment = InvocationCounter::count_increment; - if (ProfileInterpreter) { - // If no method data exists, go to profile_continue. - __ ld_ptr(Lmethod, Method::method_data_offset(), G4_scratch); - __ br_null_short(G4_scratch, Assembler::pn, Lno_mdo); - - // Increment backedge counter in the MDO - Address mdo_backedge_counter(G4_scratch, in_bytes(MethodData::backedge_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); - Address mask(G4_scratch, in_bytes(MethodData::backedge_mask_offset())); - __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, G3_scratch, O0, - (UseOnStackReplacement ? Assembler::notZero : Assembler::always), &Lforward); - __ ba_short(Loverflow); - } - - // If there's no MDO, increment counter in MethodCounters* - __ bind(Lno_mdo); - Address backedge_counter(G3_method_counters, - in_bytes(MethodCounters::backedge_counter_offset()) + - in_bytes(InvocationCounter::counter_offset())); - Address mask(G3_method_counters, in_bytes(MethodCounters::backedge_mask_offset())); - __ increment_mask_and_jump(backedge_counter, increment, mask, G4_scratch, O0, - (UseOnStackReplacement ? Assembler::notZero : Assembler::always), &Lforward); - __ bind(Loverflow); - - // notify point for loop, pass branch bytecode - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), l_cur_bcp); - - // Was an OSR adapter generated? - // O0 = osr nmethod - __ br_null_short(O0, Assembler::pn, Lforward); - - // Has the nmethod been invalidated already? - __ ldub(O0, nmethod::state_offset(), O2); - __ cmp_and_br_short(O2, nmethod::in_use, Assembler::notEqual, Assembler::pn, Lforward); - - // migrate the interpreter frame off of the stack - - __ mov(G2_thread, L7); - // save nmethod - __ mov(O0, L6); - __ set_last_Java_frame(SP, noreg); - __ call_VM_leaf(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), L7); - __ reset_last_Java_frame(); - __ mov(L7, G2_thread); - - // move OSR nmethod to I1 - __ mov(L6, I1); - - // OSR buffer to I0 - __ mov(O0, I0); - - // remove the interpreter frame - __ restore(I5_savedSP, 0, SP); - - // Jump to the osr code. - __ ld_ptr(O1, nmethod::osr_entry_point_offset(), O2); - __ jmp(O2, G0); - __ delayed()->nop(); - - } else { // not TieredCompilation - // Update Backedge branch separately from invocations - const Register G4_invoke_ctr = G4; - __ increment_backedge_counter(G3_method_counters, G4_invoke_ctr, G1_scratch); - if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(G4_invoke_ctr, G3_method_counters, G1_scratch, Lforward); - if (UseOnStackReplacement) { - - __ test_backedge_count_for_osr(O2_bumped_count, G3_method_counters, l_cur_bcp, G1_scratch); - } - } else { - if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(G4_invoke_ctr, G3_method_counters, l_cur_bcp, G1_scratch); - } - } - } - - __ bind(Lforward); - } else - // Bump bytecode pointer by displacement (take the branch) - __ add( O1_disp, Lbcp, Lbcp );// add to bc addr - - // continue with bytecode @ target - // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above, - // %%%%% and changing dispatch_next to dispatch_only - __ dispatch_next(vtos, 0, true); -} - - -// Note Condition in argument is TemplateTable::Condition -// arg scope is within class scope - -void TemplateTable::if_0cmp(Condition cc) { - // no pointers, integer only! - transition(itos, vtos); - // assume branch is more often taken than not (loops use backward branches) - __ cmp( Otos_i, 0); - __ if_cmp(ccNot(cc), false); -} - - -void TemplateTable::if_icmp(Condition cc) { - transition(itos, vtos); - __ pop_i(O1); - __ cmp(O1, Otos_i); - __ if_cmp(ccNot(cc), false); -} - - -void TemplateTable::if_nullcmp(Condition cc) { - transition(atos, vtos); - __ tst(Otos_i); - __ if_cmp(ccNot(cc), true); -} - - -void TemplateTable::if_acmp(Condition cc) { - transition(atos, vtos); - __ pop_ptr(O1); - __ verify_oop(O1); - __ verify_oop(Otos_i); - __ cmp(O1, Otos_i); - __ if_cmp(ccNot(cc), true); -} - - - -void TemplateTable::ret() { - transition(vtos, vtos); - locals_index(G3_scratch); - __ access_local_returnAddress(G3_scratch, Otos_i); - // Otos_i contains the bci, compute the bcp from that - -#ifdef ASSERT - // jsr result was labeled as an 'itos' not an 'atos' because we cannot GC - // the result. The return address (really a BCI) was stored with an - // 'astore' because JVM specs claim it's a pointer-sized thing. Hence in - // the 64-bit build the 32-bit BCI is actually in the low bits of a 64-bit - // loaded value. - { Label zzz ; - __ set (65536, G3_scratch) ; - __ cmp (Otos_i, G3_scratch) ; - __ bp( Assembler::lessEqualUnsigned, false, Assembler::xcc, Assembler::pn, zzz); - __ delayed()->nop(); - __ stop("BCI is in the wrong register half?"); - __ bind (zzz) ; - } -#endif - - __ profile_ret(vtos, Otos_i, G4_scratch); - - __ ld_ptr(Lmethod, Method::const_offset(), G3_scratch); - __ add(G3_scratch, Otos_i, G3_scratch); - __ add(G3_scratch, in_bytes(ConstMethod::codes_offset()), Lbcp); - __ dispatch_next(vtos, 0, true); -} - - -void TemplateTable::wide_ret() { - transition(vtos, vtos); - locals_index_wide(G3_scratch); - __ access_local_returnAddress(G3_scratch, Otos_i); - // Otos_i contains the bci, compute the bcp from that - - __ profile_ret(vtos, Otos_i, G4_scratch); - - __ ld_ptr(Lmethod, Method::const_offset(), G3_scratch); - __ add(G3_scratch, Otos_i, G3_scratch); - __ add(G3_scratch, in_bytes(ConstMethod::codes_offset()), Lbcp); - __ dispatch_next(vtos, 0, true); -} - - -void TemplateTable::tableswitch() { - transition(itos, vtos); - Label default_case, continue_execution; - - // align bcp - __ add(Lbcp, BytesPerInt, O1); - __ and3(O1, -BytesPerInt, O1); - // load lo, hi - __ ld(O1, 1 * BytesPerInt, O2); // Low Byte - __ ld(O1, 2 * BytesPerInt, O3); // High Byte - // Sign extend the 32 bits - __ sra ( Otos_i, 0, Otos_i ); - - // check against lo & hi - __ cmp( Otos_i, O2); - __ br( Assembler::less, false, Assembler::pn, default_case); - __ delayed()->cmp( Otos_i, O3 ); - __ br( Assembler::greater, false, Assembler::pn, default_case); - // lookup dispatch offset - __ delayed()->sub(Otos_i, O2, O2); - __ profile_switch_case(O2, O3, G3_scratch, G4_scratch); - __ sll(O2, LogBytesPerInt, O2); - __ add(O2, 3 * BytesPerInt, O2); - __ ba(continue_execution); - __ delayed()->ld(O1, O2, O2); - // handle default - __ bind(default_case); - __ profile_switch_default(O3); - __ ld(O1, 0, O2); // get default offset - // continue execution - __ bind(continue_execution); - __ add(Lbcp, O2, Lbcp); - __ dispatch_next(vtos, 0, true); -} - - -void TemplateTable::lookupswitch() { - transition(itos, itos); - __ stop("lookupswitch bytecode should have been rewritten"); -} - -void TemplateTable::fast_linearswitch() { - transition(itos, vtos); - Label loop_entry, loop, found, continue_execution; - // align bcp - __ add(Lbcp, BytesPerInt, O1); - __ and3(O1, -BytesPerInt, O1); - // set counter - __ ld(O1, BytesPerInt, O2); - __ sll(O2, LogBytesPerInt + 1, O2); // in word-pairs - __ add(O1, 2 * BytesPerInt, O3); // set first pair addr - __ ba(loop_entry); - __ delayed()->add(O3, O2, O2); // counter now points past last pair - - // table search - __ bind(loop); - __ cmp(O4, Otos_i); - __ br(Assembler::equal, true, Assembler::pn, found); - __ delayed()->ld(O3, BytesPerInt, O4); // offset -> O4 - __ inc(O3, 2 * BytesPerInt); - - __ bind(loop_entry); - __ cmp(O2, O3); - __ brx(Assembler::greaterUnsigned, true, Assembler::pt, loop); - __ delayed()->ld(O3, 0, O4); - - // default case - __ ld(O1, 0, O4); // get default offset - if (ProfileInterpreter) { - __ profile_switch_default(O3); - __ ba_short(continue_execution); - } - - // entry found -> get offset - __ bind(found); - if (ProfileInterpreter) { - __ sub(O3, O1, O3); - __ sub(O3, 2*BytesPerInt, O3); - __ srl(O3, LogBytesPerInt + 1, O3); // in word-pairs - __ profile_switch_case(O3, O1, O2, G3_scratch); - - __ bind(continue_execution); - } - __ add(Lbcp, O4, Lbcp); - __ dispatch_next(vtos, 0, true); -} - - -void TemplateTable::fast_binaryswitch() { - transition(itos, vtos); - // Implementation using the following core algorithm: (copied from Intel) - // - // int binary_search(int key, LookupswitchPair* array, int n) { - // // Binary search according to "Methodik des Programmierens" by - // // Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. - // int i = 0; - // int j = n; - // while (i+1 < j) { - // // invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) - // // with Q: for all i: 0 <= i < n: key < a[i] - // // where a stands for the array and assuming that the (inexisting) - // // element a[n] is infinitely big. - // int h = (i + j) >> 1; - // // i < h < j - // if (key < array[h].fast_match()) { - // j = h; - // } else { - // i = h; - // } - // } - // // R: a[i] <= key < a[i+1] or Q - // // (i.e., if key is within array, i is the correct index) - // return i; - // } - - // register allocation - assert(Otos_i == O0, "alias checking"); - const Register Rkey = Otos_i; // already set (tosca) - const Register Rarray = O1; - const Register Ri = O2; - const Register Rj = O3; - const Register Rh = O4; - const Register Rscratch = O5; - - const int log_entry_size = 3; - const int entry_size = 1 << log_entry_size; - - Label found; - // Find Array start - __ add(Lbcp, 3 * BytesPerInt, Rarray); - __ and3(Rarray, -BytesPerInt, Rarray); - // initialize i & j (in delay slot) - __ clr( Ri ); - - // and start - Label entry; - __ ba(entry); - __ delayed()->ld( Rarray, -BytesPerInt, Rj); - // (Rj is already in the native byte-ordering.) - - // binary search loop - { Label loop; - __ bind( loop ); - // int h = (i + j) >> 1; - __ sra( Rh, 1, Rh ); - // if (key < array[h].fast_match()) { - // j = h; - // } else { - // i = h; - // } - __ sll( Rh, log_entry_size, Rscratch ); - __ ld( Rarray, Rscratch, Rscratch ); - // (Rscratch is already in the native byte-ordering.) - __ cmp( Rkey, Rscratch ); - __ movcc( Assembler::less, false, Assembler::icc, Rh, Rj ); // j = h if (key < array[h].fast_match()) - __ movcc( Assembler::greaterEqual, false, Assembler::icc, Rh, Ri ); // i = h if (key >= array[h].fast_match()) - - // while (i+1 < j) - __ bind( entry ); - __ add( Ri, 1, Rscratch ); - __ cmp(Rscratch, Rj); - __ br( Assembler::less, true, Assembler::pt, loop ); - __ delayed()->add( Ri, Rj, Rh ); // start h = i + j >> 1; - } - - // end of binary search, result index is i (must check again!) - Label default_case; - Label continue_execution; - if (ProfileInterpreter) { - __ mov( Ri, Rh ); // Save index in i for profiling - } - __ sll( Ri, log_entry_size, Ri ); - __ ld( Rarray, Ri, Rscratch ); - // (Rscratch is already in the native byte-ordering.) - __ cmp( Rkey, Rscratch ); - __ br( Assembler::notEqual, true, Assembler::pn, default_case ); - __ delayed()->ld( Rarray, -2 * BytesPerInt, Rj ); // load default offset -> j - - // entry found -> j = offset - __ inc( Ri, BytesPerInt ); - __ profile_switch_case(Rh, Rj, Rscratch, Rkey); - __ ld( Rarray, Ri, Rj ); - // (Rj is already in the native byte-ordering.) - - if (ProfileInterpreter) { - __ ba_short(continue_execution); - } - - __ bind(default_case); // fall through (if not profiling) - __ profile_switch_default(Ri); - - __ bind(continue_execution); - __ add( Lbcp, Rj, Lbcp ); - __ dispatch_next(vtos, 0, true); -} - - -void TemplateTable::_return(TosState state) { - transition(state, state); - assert(_desc->calls_vm(), "inconsistent calls_vm information"); - - if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { - assert(state == vtos, "only valid state"); - __ mov(G0, G3_scratch); - __ access_local_ptr(G3_scratch, Otos_i); - __ load_klass(Otos_i, O2); - __ set(JVM_ACC_HAS_FINALIZER, G3); - __ ld(O2, in_bytes(Klass::access_flags_offset()), O2); - __ andcc(G3, O2, G0); - Label skip_register_finalizer; - __ br(Assembler::zero, false, Assembler::pn, skip_register_finalizer); - __ delayed()->nop(); - - // Call out to do finalizer registration - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), Otos_i); - - __ bind(skip_register_finalizer); - } - - if (_desc->bytecode() != Bytecodes::_return_register_finalizer) { - Label no_safepoint; - __ ldx(Address(G2_thread, Thread::polling_page_offset()), G3_scratch, 0); - __ btst(SafepointMechanism::poll_bit(), G3_scratch); - __ br(Assembler::zero, false, Assembler::pt, no_safepoint); - __ delayed()->nop(); - __ push(state); - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)); - __ pop(state); - __ bind(no_safepoint); - } - - // Narrow result if state is itos but result type is smaller. - // Need to narrow in the return bytecode rather than in generate_return_entry - // since compiled code callers expect the result to already be narrowed. - if (state == itos) { - __ narrow(Otos_i); - } - __ remove_activation(state, /* throw_monitor_exception */ true); - - // The caller's SP was adjusted upon method entry to accomodate - // the callee's non-argument locals. Undo that adjustment. - __ ret(); // return to caller - __ delayed()->restore(I5_savedSP, G0, SP); -} - - -// ---------------------------------------------------------------------------- -// Volatile variables demand their effects be made known to all CPU's in -// order. Store buffers on most chips allow reads & writes to reorder; the -// JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of -// memory barrier (i.e., it's not sufficient that the interpreter does not -// reorder volatile references, the hardware also must not reorder them). -// -// According to the new Java Memory Model (JMM): -// (1) All volatiles are serialized wrt to each other. -// ALSO reads & writes act as aquire & release, so: -// (2) A read cannot let unrelated NON-volatile memory refs that happen after -// the read float up to before the read. It's OK for non-volatile memory refs -// that happen before the volatile read to float down below it. -// (3) Similar a volatile write cannot let unrelated NON-volatile memory refs -// that happen BEFORE the write float down to after the write. It's OK for -// non-volatile memory refs that happen after the volatile write to float up -// before it. -// -// We only put in barriers around volatile refs (they are expensive), not -// _between_ memory refs (that would require us to track the flavor of the -// previous memory refs). Requirements (2) and (3) require some barriers -// before volatile stores and after volatile loads. These nearly cover -// requirement (1) but miss the volatile-store-volatile-load case. This final -// case is placed after volatile-stores although it could just as well go -// before volatile-loads. -void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint) { - // Helper function to insert a is-volatile test and memory barrier - // All current sparc implementations run in TSO, needing only StoreLoad - if ((order_constraint & Assembler::StoreLoad) == 0) return; - __ membar( order_constraint ); -} - -// ---------------------------------------------------------------------------- -void TemplateTable::resolve_cache_and_index(int byte_no, - Register Rcache, - Register index, - size_t index_size) { - // Depends on cpCacheOop layout! - - Label resolved; - Bytecodes::Code code = bytecode(); - switch (code) { - case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; - case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; - } - - assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); - __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, Lbyte_code, byte_no, 1, index_size); - __ cmp(Lbyte_code, code); // have we resolved this bytecode? - __ br(Assembler::equal, false, Assembler::pt, resolved); - __ delayed()->set(code, O1); - - address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); - // first time invocation - must resolve first - __ call_VM(noreg, entry, O1); - // Update registers with resolved info - __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); - __ bind(resolved); -} - -void TemplateTable::load_invoke_cp_cache_entry(int byte_no, - Register method, - Register itable_index, - Register flags, - bool is_invokevirtual, - bool is_invokevfinal, - bool is_invokedynamic) { - // Uses both G3_scratch and G4_scratch - Register cache = G3_scratch; - Register index = G4_scratch; - assert_different_registers(cache, method, itable_index); - - // determine constant pool cache field offsets - assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant"); - const int method_offset = in_bytes( - ConstantPoolCache::base_offset() + - ((byte_no == f2_byte) - ? ConstantPoolCacheEntry::f2_offset() - : ConstantPoolCacheEntry::f1_offset() - ) - ); - const int flags_offset = in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::flags_offset()); - // access constant pool cache fields - const int index_offset = in_bytes(ConstantPoolCache::base_offset() + - ConstantPoolCacheEntry::f2_offset()); - - if (is_invokevfinal) { - __ get_cache_and_index_at_bcp(cache, index, 1); - __ ld_ptr(Address(cache, method_offset), method); - } else { - size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2)); - resolve_cache_and_index(byte_no, cache, index, index_size); - __ ld_ptr(Address(cache, method_offset), method); - } - - if (itable_index != noreg) { - // pick up itable or appendix index from f2 also: - __ ld_ptr(Address(cache, index_offset), itable_index); - } - __ ld_ptr(Address(cache, flags_offset), flags); -} - -// The Rcache register must be set before call -void TemplateTable::load_field_cp_cache_entry(Register Robj, - Register Rcache, - Register index, - Register Roffset, - Register Rflags, - bool is_static) { - assert_different_registers(Rcache, Rflags, Roffset, Lscratch); - - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags); - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset); - if (is_static) { - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset(), Robj); - const int mirror_offset = in_bytes(Klass::java_mirror_offset()); - __ ld_ptr( Robj, mirror_offset, Robj); - __ resolve_oop_handle(Robj, Lscratch); - } -} - -// The registers Rcache and index expected to be set before call. -// Correct values of the Rcache and index registers are preserved. -void TemplateTable::jvmti_post_field_access(Register Rcache, - Register index, - bool is_static, - bool has_tos) { - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - if (JvmtiExport::can_post_field_access()) { - // Check to see if a field access watch has been set before we take - // the time to call into the VM. - Label Label1; - assert_different_registers(Rcache, index, G1_scratch); - AddressLiteral get_field_access_count_addr(JvmtiExport::get_field_access_count_addr()); - __ load_contents(get_field_access_count_addr, G1_scratch); - __ cmp_and_br_short(G1_scratch, 0, Assembler::equal, Assembler::pt, Label1); - - __ add(Rcache, in_bytes(cp_base_offset), Rcache); - - if (is_static) { - __ clr(Otos_i); - } else { - if (has_tos) { - // save object pointer before call_VM() clobbers it - __ push_ptr(Otos_i); // put object on tos where GC wants it. - } else { - // Load top of stack (do not pop the value off the stack); - __ ld_ptr(Lesp, Interpreter::expr_offset_in_bytes(0), Otos_i); - } - __ verify_oop(Otos_i); - } - // Otos_i: object pointer or NULL if static - // Rcache: cache entry pointer - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_access), - Otos_i, Rcache); - if (!is_static && has_tos) { - __ pop_ptr(Otos_i); // restore object pointer - __ verify_oop(Otos_i); - } - __ get_cache_and_index_at_bcp(Rcache, index, 1); - __ bind(Label1); - } -} - -void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) { - transition(vtos, vtos); - - Register Rcache = G3_scratch; - Register index = G4_scratch; - Register Rclass = Rcache; - Register Roffset= G4_scratch; - Register Rflags = G1_scratch; - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - resolve_cache_and_index(byte_no, Rcache, index, sizeof(u2)); - jvmti_post_field_access(Rcache, index, is_static, false); - load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static); - - if (!is_static) { - pop_and_check_object(Rclass); - } else { - __ verify_oop(Rclass); - } - - Label exit; - - Assembler::Membar_mask_bits membar_bits = - Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore); - - if (__ membar_has_effect(membar_bits)) { - // Get volatile flag - __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch); - __ and3(Rflags, Lscratch, Lscratch); - } - - Label checkVolatile; - - // compute field type - Label notByte, notBool, notInt, notShort, notChar, notLong, notFloat, notObj; - __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags); - // Make sure we don't need to mask Rflags after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - - // Check atos before itos for getstatic, more likely (in Queens at least) - __ cmp(Rflags, atos); - __ br(Assembler::notEqual, false, Assembler::pt, notObj); - __ delayed() ->cmp(Rflags, itos); - - // atos - do_oop_load(_masm, Rclass, Roffset, 0, Otos_i, noreg); - __ verify_oop(Otos_i); - __ push(atos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_agetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notObj); - - // cmp(Rflags, itos); - __ br(Assembler::notEqual, false, Assembler::pt, notInt); - __ delayed() ->cmp(Rflags, ltos); - - // itos - __ ld(Rclass, Roffset, Otos_i); - __ push(itos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_igetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notInt); - - // cmp(Rflags, ltos); - __ br(Assembler::notEqual, false, Assembler::pt, notLong); - __ delayed() ->cmp(Rflags, btos); - - // ltos - // load must be atomic - __ ld_long(Rclass, Roffset, Otos_l); - __ push(ltos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_lgetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notLong); - - // cmp(Rflags, btos); - __ br(Assembler::notEqual, false, Assembler::pt, notByte); - __ delayed() ->cmp(Rflags, ztos); - - // btos - __ ldsb(Rclass, Roffset, Otos_i); - __ push(itos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notByte); - - // cmp(Rflags, ztos); - __ br(Assembler::notEqual, false, Assembler::pt, notBool); - __ delayed() ->cmp(Rflags, ctos); - - // ztos - __ ldsb(Rclass, Roffset, Otos_i); - __ push(itos); - if (!is_static && rc == may_rewrite) { - // use btos rewriting, no truncating to t/f bit is needed for getfield. - patch_bytecode(Bytecodes::_fast_bgetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notBool); - - // cmp(Rflags, ctos); - __ br(Assembler::notEqual, false, Assembler::pt, notChar); - __ delayed() ->cmp(Rflags, stos); - - // ctos - __ lduh(Rclass, Roffset, Otos_i); - __ push(itos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_cgetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notChar); - - // cmp(Rflags, stos); - __ br(Assembler::notEqual, false, Assembler::pt, notShort); - __ delayed() ->cmp(Rflags, ftos); - - // stos - __ ldsh(Rclass, Roffset, Otos_i); - __ push(itos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_sgetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notShort); - - - // cmp(Rflags, ftos); - __ br(Assembler::notEqual, false, Assembler::pt, notFloat); - __ delayed() ->tst(Lscratch); - - // ftos - __ ldf(FloatRegisterImpl::S, Rclass, Roffset, Ftos_f); - __ push(ftos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_fgetfield, G3_scratch, G4_scratch); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - - __ bind(notFloat); - - - // dtos - __ ldf(FloatRegisterImpl::D, Rclass, Roffset, Ftos_d); - __ push(dtos); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_dgetfield, G3_scratch, G4_scratch); - } - - __ bind(checkVolatile); - if (__ membar_has_effect(membar_bits)) { - // __ tst(Lscratch); executed in delay slot - __ br(Assembler::zero, false, Assembler::pt, exit); - __ delayed()->nop(); - volatile_barrier(membar_bits); - } - - __ bind(exit); -} - -void TemplateTable::getfield(int byte_no) { - getfield_or_static(byte_no, false); -} - -void TemplateTable::nofast_getfield(int byte_no) { - getfield_or_static(byte_no, false, may_not_rewrite); -} - -void TemplateTable::getstatic(int byte_no) { - getfield_or_static(byte_no, true); -} - -void TemplateTable::fast_accessfield(TosState state) { - transition(atos, state); - Register Rcache = G3_scratch; - Register index = G4_scratch; - Register Roffset = G4_scratch; - Register Rflags = Rcache; - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - __ get_cache_and_index_at_bcp(Rcache, index, 1); - jvmti_post_field_access(Rcache, index, /*is_static*/false, /*has_tos*/true); - - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset); - - __ null_check(Otos_i); - __ verify_oop(Otos_i); - - Label exit; - - Assembler::Membar_mask_bits membar_bits = - Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore); - if (__ membar_has_effect(membar_bits)) { - // Get volatile flag - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Rflags); - __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch); - } - - switch (bytecode()) { - case Bytecodes::_fast_bgetfield: - __ ldsb(Otos_i, Roffset, Otos_i); - break; - case Bytecodes::_fast_cgetfield: - __ lduh(Otos_i, Roffset, Otos_i); - break; - case Bytecodes::_fast_sgetfield: - __ ldsh(Otos_i, Roffset, Otos_i); - break; - case Bytecodes::_fast_igetfield: - __ ld(Otos_i, Roffset, Otos_i); - break; - case Bytecodes::_fast_lgetfield: - __ ld_long(Otos_i, Roffset, Otos_l); - break; - case Bytecodes::_fast_fgetfield: - __ ldf(FloatRegisterImpl::S, Otos_i, Roffset, Ftos_f); - break; - case Bytecodes::_fast_dgetfield: - __ ldf(FloatRegisterImpl::D, Otos_i, Roffset, Ftos_d); - break; - case Bytecodes::_fast_agetfield: - do_oop_load(_masm, Otos_i, Roffset, 0, Otos_i, noreg); - break; - default: - ShouldNotReachHere(); - } - - if (__ membar_has_effect(membar_bits)) { - __ btst(Lscratch, Rflags); - __ br(Assembler::zero, false, Assembler::pt, exit); - __ delayed()->nop(); - volatile_barrier(membar_bits); - __ bind(exit); - } - - if (state == atos) { - __ verify_oop(Otos_i); // does not blow flags! - } -} - -void TemplateTable::jvmti_post_fast_field_mod() { - if (JvmtiExport::can_post_field_modification()) { - // Check to see if a field modification watch has been set before we take - // the time to call into the VM. - Label done; - AddressLiteral get_field_modification_count_addr(JvmtiExport::get_field_modification_count_addr()); - __ load_contents(get_field_modification_count_addr, G4_scratch); - __ cmp_and_br_short(G4_scratch, 0, Assembler::equal, Assembler::pt, done); - __ pop_ptr(G4_scratch); // copy the object pointer from tos - __ verify_oop(G4_scratch); - __ push_ptr(G4_scratch); // put the object pointer back on tos - __ get_cache_entry_pointer_at_bcp(G1_scratch, G3_scratch, 1); - // Save tos values before call_VM() clobbers them. Since we have - // to do it for every data type, we use the saved values as the - // jvalue object. - switch (bytecode()) { // save tos values before call_VM() clobbers them - case Bytecodes::_fast_aputfield: __ push_ptr(Otos_i); break; - case Bytecodes::_fast_bputfield: // fall through - case Bytecodes::_fast_zputfield: // fall through - case Bytecodes::_fast_sputfield: // fall through - case Bytecodes::_fast_cputfield: // fall through - case Bytecodes::_fast_iputfield: __ push_i(Otos_i); break; - case Bytecodes::_fast_dputfield: __ push_d(Ftos_d); break; - case Bytecodes::_fast_fputfield: __ push_f(Ftos_f); break; - // get words in right order for use as jvalue object - case Bytecodes::_fast_lputfield: __ push_l(Otos_l); break; - } - // setup pointer to jvalue object - __ mov(Lesp, G3_scratch); __ inc(G3_scratch, wordSize); - // G4_scratch: object pointer - // G1_scratch: cache entry pointer - // G3_scratch: jvalue object on the stack - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), G4_scratch, G1_scratch, G3_scratch); - switch (bytecode()) { // restore tos values - case Bytecodes::_fast_aputfield: __ pop_ptr(Otos_i); break; - case Bytecodes::_fast_bputfield: // fall through - case Bytecodes::_fast_zputfield: // fall through - case Bytecodes::_fast_sputfield: // fall through - case Bytecodes::_fast_cputfield: // fall through - case Bytecodes::_fast_iputfield: __ pop_i(Otos_i); break; - case Bytecodes::_fast_dputfield: __ pop_d(Ftos_d); break; - case Bytecodes::_fast_fputfield: __ pop_f(Ftos_f); break; - case Bytecodes::_fast_lputfield: __ pop_l(Otos_l); break; - } - __ bind(done); - } -} - -// The registers Rcache and index expected to be set before call. -// The function may destroy various registers, just not the Rcache and index registers. -void TemplateTable::jvmti_post_field_mod(Register Rcache, Register index, bool is_static) { - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - if (JvmtiExport::can_post_field_modification()) { - // Check to see if a field modification watch has been set before we take - // the time to call into the VM. - Label Label1; - assert_different_registers(Rcache, index, G1_scratch); - AddressLiteral get_field_modification_count_addr(JvmtiExport::get_field_modification_count_addr()); - __ load_contents(get_field_modification_count_addr, G1_scratch); - __ cmp_and_br_short(G1_scratch, 0, Assembler::zero, Assembler::pt, Label1); - - // The Rcache and index registers have been already set. - // This allows to eliminate this call but the Rcache and index - // registers must be correspondingly used after this line. - __ get_cache_and_index_at_bcp(G1_scratch, G4_scratch, 1); - - __ add(G1_scratch, in_bytes(cp_base_offset), G3_scratch); - if (is_static) { - // Life is simple. Null out the object pointer. - __ clr(G4_scratch); - } else { - Register Rflags = G1_scratch; - // Life is harder. The stack holds the value on top, followed by the - // object. We don't know the size of the value, though; it could be - // one or two words depending on its type. As a result, we must find - // the type to determine where the object is. - - Label two_word, valsizeknown; - __ ld_ptr(G1_scratch, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags); - __ mov(Lesp, G4_scratch); - __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags); - // Make sure we don't need to mask Rflags after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - __ cmp(Rflags, ltos); - __ br(Assembler::equal, false, Assembler::pt, two_word); - __ delayed()->cmp(Rflags, dtos); - __ br(Assembler::equal, false, Assembler::pt, two_word); - __ delayed()->nop(); - __ inc(G4_scratch, Interpreter::expr_offset_in_bytes(1)); - __ ba_short(valsizeknown); - __ bind(two_word); - - __ inc(G4_scratch, Interpreter::expr_offset_in_bytes(2)); - - __ bind(valsizeknown); - // setup object pointer - __ ld_ptr(G4_scratch, 0, G4_scratch); - __ verify_oop(G4_scratch); - } - // setup pointer to jvalue object - __ mov(Lesp, G1_scratch); __ inc(G1_scratch, wordSize); - // G4_scratch: object pointer or NULL if static - // G3_scratch: cache entry pointer - // G1_scratch: jvalue object on the stack - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_field_modification), - G4_scratch, G3_scratch, G1_scratch); - __ get_cache_and_index_at_bcp(Rcache, index, 1); - __ bind(Label1); - } -} - -void TemplateTable::pop_and_check_object(Register r) { - __ pop_ptr(r); - __ null_check(r); // for field access must check obj. - __ verify_oop(r); -} - -void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { - transition(vtos, vtos); - Register Rcache = G3_scratch; - Register index = G4_scratch; - Register Rclass = Rcache; - Register Roffset= G4_scratch; - Register Rflags = G1_scratch; - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - resolve_cache_and_index(byte_no, Rcache, index, sizeof(u2)); - jvmti_post_field_mod(Rcache, index, is_static); - load_field_cp_cache_entry(Rclass, Rcache, index, Roffset, Rflags, is_static); - - Assembler::Membar_mask_bits read_bits = - Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore); - Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad; - - Label notVolatile, checkVolatile, exit; - if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) { - __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch); - __ and3(Rflags, Lscratch, Lscratch); - - if (__ membar_has_effect(read_bits)) { - __ cmp_and_br_short(Lscratch, 0, Assembler::equal, Assembler::pt, notVolatile); - volatile_barrier(read_bits); - __ bind(notVolatile); - } - } - - __ srl(Rflags, ConstantPoolCacheEntry::tos_state_shift, Rflags); - // Make sure we don't need to mask Rflags after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - - // compute field type - Label notInt, notShort, notChar, notObj, notByte, notBool, notLong, notFloat; - - if (is_static) { - // putstatic with object type most likely, check that first - __ cmp(Rflags, atos); - __ br(Assembler::notEqual, false, Assembler::pt, notObj); - __ delayed()->cmp(Rflags, itos); - - // atos - { - __ pop_ptr(); - __ verify_oop(Otos_i); - do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch); - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notObj); - // cmp(Rflags, itos); - __ br(Assembler::notEqual, false, Assembler::pt, notInt); - __ delayed()->cmp(Rflags, btos); - - // itos - { - __ pop_i(); - __ st(Otos_i, Rclass, Roffset); - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notInt); - } else { - // putfield with int type most likely, check that first - __ cmp(Rflags, itos); - __ br(Assembler::notEqual, false, Assembler::pt, notInt); - __ delayed()->cmp(Rflags, atos); - - // itos - { - __ pop_i(); - pop_and_check_object(Rclass); - __ st(Otos_i, Rclass, Roffset); - if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_iputfield, G3_scratch, G4_scratch, true, byte_no); - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notInt); - // cmp(Rflags, atos); - __ br(Assembler::notEqual, false, Assembler::pt, notObj); - __ delayed()->cmp(Rflags, btos); - - // atos - { - __ pop_ptr(); - pop_and_check_object(Rclass); - __ verify_oop(Otos_i); - do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch); - if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch, true, byte_no); - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notObj); - } - - // cmp(Rflags, btos); - __ br(Assembler::notEqual, false, Assembler::pt, notByte); - __ delayed()->cmp(Rflags, ztos); - - // btos - { - __ pop_i(); - if (!is_static) pop_and_check_object(Rclass); - __ stb(Otos_i, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_bputfield, G3_scratch, G4_scratch, true, byte_no); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notByte); - - // cmp(Rflags, btos); - __ br(Assembler::notEqual, false, Assembler::pt, notBool); - __ delayed()->cmp(Rflags, ltos); - - // ztos - { - __ pop_i(); - if (!is_static) pop_and_check_object(Rclass); - __ and3(Otos_i, 1, Otos_i); - __ stb(Otos_i, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_zputfield, G3_scratch, G4_scratch, true, byte_no); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notBool); - // cmp(Rflags, ltos); - __ br(Assembler::notEqual, false, Assembler::pt, notLong); - __ delayed()->cmp(Rflags, ctos); - - // ltos - { - __ pop_l(); - if (!is_static) pop_and_check_object(Rclass); - __ st_long(Otos_l, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_lputfield, G3_scratch, G4_scratch, true, byte_no); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notLong); - // cmp(Rflags, ctos); - __ br(Assembler::notEqual, false, Assembler::pt, notChar); - __ delayed()->cmp(Rflags, stos); - - // ctos (char) - { - __ pop_i(); - if (!is_static) pop_and_check_object(Rclass); - __ sth(Otos_i, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_cputfield, G3_scratch, G4_scratch, true, byte_no); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notChar); - // cmp(Rflags, stos); - __ br(Assembler::notEqual, false, Assembler::pt, notShort); - __ delayed()->cmp(Rflags, ftos); - - // stos (short) - { - __ pop_i(); - if (!is_static) pop_and_check_object(Rclass); - __ sth(Otos_i, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_sputfield, G3_scratch, G4_scratch, true, byte_no); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notShort); - // cmp(Rflags, ftos); - __ br(Assembler::notZero, false, Assembler::pt, notFloat); - __ delayed()->nop(); - - // ftos - { - __ pop_f(); - if (!is_static) pop_and_check_object(Rclass); - __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_fputfield, G3_scratch, G4_scratch, true, byte_no); - } - __ ba(checkVolatile); - __ delayed()->tst(Lscratch); - } - - __ bind(notFloat); - - // dtos - { - __ pop_d(); - if (!is_static) pop_and_check_object(Rclass); - __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset); - if (!is_static && rc == may_rewrite) { - patch_bytecode(Bytecodes::_fast_dputfield, G3_scratch, G4_scratch, true, byte_no); - } - } - - __ bind(checkVolatile); - __ tst(Lscratch); - - if (__ membar_has_effect(write_bits)) { - // __ tst(Lscratch); in delay slot - __ br(Assembler::zero, false, Assembler::pt, exit); - __ delayed()->nop(); - volatile_barrier(Assembler::StoreLoad); - __ bind(exit); - } -} - -void TemplateTable::fast_storefield(TosState state) { - transition(state, vtos); - Register Rcache = G3_scratch; - Register Rclass = Rcache; - Register Roffset= G4_scratch; - Register Rflags = G1_scratch; - ByteSize cp_base_offset = ConstantPoolCache::base_offset(); - - jvmti_post_fast_field_mod(); - - __ get_cache_and_index_at_bcp(Rcache, G4_scratch, 1); - - Assembler::Membar_mask_bits read_bits = - Assembler::Membar_mask_bits(Assembler::LoadStore | Assembler::StoreStore); - Assembler::Membar_mask_bits write_bits = Assembler::StoreLoad; - - Label notVolatile, checkVolatile, exit; - if (__ membar_has_effect(read_bits) || __ membar_has_effect(write_bits)) { - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::flags_offset(), Rflags); - __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch); - __ and3(Rflags, Lscratch, Lscratch); - if (__ membar_has_effect(read_bits)) { - __ cmp_and_br_short(Lscratch, 0, Assembler::equal, Assembler::pt, notVolatile); - volatile_barrier(read_bits); - __ bind(notVolatile); - } - } - - __ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f2_offset(), Roffset); - pop_and_check_object(Rclass); - - switch (bytecode()) { - case Bytecodes::_fast_zputfield: __ and3(Otos_i, 1, Otos_i); // fall through to bputfield - case Bytecodes::_fast_bputfield: __ stb(Otos_i, Rclass, Roffset); break; - case Bytecodes::_fast_cputfield: /* fall through */ - case Bytecodes::_fast_sputfield: __ sth(Otos_i, Rclass, Roffset); break; - case Bytecodes::_fast_iputfield: __ st(Otos_i, Rclass, Roffset); break; - case Bytecodes::_fast_lputfield: __ st_long(Otos_l, Rclass, Roffset); break; - case Bytecodes::_fast_fputfield: - __ stf(FloatRegisterImpl::S, Ftos_f, Rclass, Roffset); - break; - case Bytecodes::_fast_dputfield: - __ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset); - break; - case Bytecodes::_fast_aputfield: - do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch); - break; - default: - ShouldNotReachHere(); - } - - if (__ membar_has_effect(write_bits)) { - __ cmp_and_br_short(Lscratch, 0, Assembler::equal, Assembler::pt, exit); - volatile_barrier(Assembler::StoreLoad); - __ bind(exit); - } -} - -void TemplateTable::putfield(int byte_no) { - putfield_or_static(byte_no, false); -} - -void TemplateTable::nofast_putfield(int byte_no) { - putfield_or_static(byte_no, false, may_not_rewrite); -} - -void TemplateTable::putstatic(int byte_no) { - putfield_or_static(byte_no, true); -} - -void TemplateTable::fast_xaccess(TosState state) { - transition(vtos, state); - Register Rcache = G3_scratch; - Register Roffset = G4_scratch; - Register Rflags = G4_scratch; - Register Rreceiver = Lscratch; - - __ ld_ptr(Llocals, 0, Rreceiver); - - // access constant pool cache (is resolved) - __ get_cache_and_index_at_bcp(Rcache, G4_scratch, 2); - __ ld_ptr(Rcache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset(), Roffset); - __ add(Lbcp, 1, Lbcp); // needed to report exception at the correct bcp - - __ verify_oop(Rreceiver); - __ null_check(Rreceiver); - if (state == atos) { - do_oop_load(_masm, Rreceiver, Roffset, 0, Otos_i, noreg); - } else if (state == itos) { - __ ld (Rreceiver, Roffset, Otos_i) ; - } else if (state == ftos) { - __ ldf(FloatRegisterImpl::S, Rreceiver, Roffset, Ftos_f); - } else { - ShouldNotReachHere(); - } - - Assembler::Membar_mask_bits membar_bits = - Assembler::Membar_mask_bits(Assembler::LoadLoad | Assembler::LoadStore); - if (__ membar_has_effect(membar_bits)) { - - // Get is_volatile value in Rflags and check if membar is needed - __ ld_ptr(Rcache, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset(), Rflags); - - // Test volatile - Label notVolatile; - __ set((1 << ConstantPoolCacheEntry::is_volatile_shift), Lscratch); - __ btst(Rflags, Lscratch); - __ br(Assembler::zero, false, Assembler::pt, notVolatile); - __ delayed()->nop(); - volatile_barrier(membar_bits); - __ bind(notVolatile); - } - - __ interp_verify_oop(Otos_i, state, __FILE__, __LINE__); - __ sub(Lbcp, 1, Lbcp); -} - -//---------------------------------------------------------------------------------------------------- -// Calls - -void TemplateTable::count_calls(Register method, Register temp) { - // implemented elsewhere - ShouldNotReachHere(); -} - -void TemplateTable::prepare_invoke(int byte_no, - Register method, // linked method (or i-klass) - Register ra, // return address - Register index, // itable index, MethodType, etc. - Register recv, // if caller wants to see it - Register flags // if caller wants to test it - ) { - // determine flags - const Bytecodes::Code code = bytecode(); - const bool is_invokeinterface = code == Bytecodes::_invokeinterface; - const bool is_invokedynamic = code == Bytecodes::_invokedynamic; - const bool is_invokehandle = code == Bytecodes::_invokehandle; - const bool is_invokevirtual = code == Bytecodes::_invokevirtual; - const bool is_invokespecial = code == Bytecodes::_invokespecial; - const bool load_receiver = (recv != noreg); - assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), ""); - assert(recv == noreg || recv == O0, ""); - assert(flags == noreg || flags == O1, ""); - - // setup registers & access constant pool cache - if (recv == noreg) recv = O0; - if (flags == noreg) flags = O1; - const Register temp = O2; - assert_different_registers(method, ra, index, recv, flags, temp); - - load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic); - - __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore - - // maybe push appendix to arguments - if (is_invokedynamic || is_invokehandle) { - Label L_no_push; - __ set((1 << ConstantPoolCacheEntry::has_appendix_shift), temp); - __ btst(flags, temp); - __ br(Assembler::zero, false, Assembler::pt, L_no_push); - __ delayed()->nop(); - // Push the appendix as a trailing parameter. - // This must be done before we get the receiver, - // since the parameter_size includes it. - __ load_resolved_reference_at_index(temp, index, /*tmp*/recv); - __ verify_oop(temp); - __ push_ptr(temp); // push appendix (MethodType, CallSite, etc.) - __ bind(L_no_push); - } - - // load receiver if needed (after appendix is pushed so parameter size is correct) - if (load_receiver) { - __ and3(flags, ConstantPoolCacheEntry::parameter_size_mask, temp); // get parameter size - __ load_receiver(temp, recv); // __ argument_address uses Gargs but we need Lesp - __ verify_oop(recv); - } - - // compute return type - __ srl(flags, ConstantPoolCacheEntry::tos_state_shift, ra); - // Make sure we don't need to mask flags after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - // load return address - { - const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code); - AddressLiteral table(table_addr); - __ set(table, temp); - __ sll(ra, LogBytesPerWord, ra); - __ ld_ptr(Address(temp, ra), ra); - } -} - - -void TemplateTable::generate_vtable_call(Register Rrecv, Register Rindex, Register Rret) { - Register Rtemp = G4_scratch; - Register Rcall = Rindex; - assert_different_registers(Rcall, G5_method, Gargs, Rret); - - // get target Method* & entry point - __ lookup_virtual_method(Rrecv, Rindex, G5_method); - __ profile_arguments_type(G5_method, Rcall, Gargs, true); - __ call_from_interpreter(Rcall, Gargs, Rret); -} - -void TemplateTable::invokevirtual(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f2_byte, "use this argument"); - - Register Rscratch = G3_scratch; - Register Rtemp = G4_scratch; - Register Rret = Lscratch; - Register O0_recv = O0; - Label notFinal; - - load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Rret, true, false, false); - __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore - - // Check for vfinal - __ set((1 << ConstantPoolCacheEntry::is_vfinal_shift), G4_scratch); - __ btst(Rret, G4_scratch); - __ br(Assembler::zero, false, Assembler::pt, notFinal); - __ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters - - if (RewriteBytecodes && !UseSharedSpaces && !DumpSharedSpaces) { - patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp); - } - - invokevfinal_helper(Rscratch, Rret); - - __ bind(notFinal); - - __ mov(G5_method, Rscratch); // better scratch register - __ load_receiver(G4_scratch, O0_recv); // gets receiverOop - // receiver is in O0_recv - __ verify_oop(O0_recv); - - // get return address - AddressLiteral table(Interpreter::invoke_return_entry_table()); - __ set(table, Rtemp); - __ srl(Rret, ConstantPoolCacheEntry::tos_state_shift, Rret); // get return type - // Make sure we don't need to mask Rret after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - __ sll(Rret, LogBytesPerWord, Rret); - __ ld_ptr(Rtemp, Rret, Rret); // get return address - - // get receiver klass - __ null_check(O0_recv, oopDesc::klass_offset_in_bytes()); - __ load_klass(O0_recv, O0_recv); - __ verify_klass_ptr(O0_recv); - - __ profile_virtual_call(O0_recv, O4); - - generate_vtable_call(O0_recv, Rscratch, Rret); -} - -void TemplateTable::fast_invokevfinal(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f2_byte, "use this argument"); - - load_invoke_cp_cache_entry(byte_no, G5_method, noreg, Lscratch, true, - /*is_invokevfinal*/true, false); - __ mov(SP, O5_savedSP); // record SP that we wanted the callee to restore - invokevfinal_helper(G3_scratch, Lscratch); -} - -void TemplateTable::invokevfinal_helper(Register Rscratch, Register Rret) { - Register Rtemp = G4_scratch; - - // Load receiver from stack slot - __ ld_ptr(G5_method, in_bytes(Method::const_offset()), G4_scratch); - __ lduh(G4_scratch, in_bytes(ConstMethod::size_of_parameters_offset()), G4_scratch); - __ load_receiver(G4_scratch, O0); - - // receiver NULL check - __ null_check(O0); - - __ profile_final_call(O4); - __ profile_arguments_type(G5_method, Rscratch, Gargs, true); - - // get return address - AddressLiteral table(Interpreter::invoke_return_entry_table()); - __ set(table, Rtemp); - __ srl(Rret, ConstantPoolCacheEntry::tos_state_shift, Rret); // get return type - // Make sure we don't need to mask Rret after the above shift - ConstantPoolCacheEntry::verify_tos_state_shift(); - __ sll(Rret, LogBytesPerWord, Rret); - __ ld_ptr(Rtemp, Rret, Rret); // get return address - - - // do the call - __ call_from_interpreter(Rscratch, Gargs, Rret); -} - - -void TemplateTable::invokespecial(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f1_byte, "use this argument"); - - const Register Rret = Lscratch; - const Register O0_recv = O0; - const Register Rscratch = G3_scratch; - - prepare_invoke(byte_no, G5_method, Rret, noreg, O0_recv); // get receiver also for null check - __ null_check(O0_recv); - - // do the call - __ profile_call(O4); - __ profile_arguments_type(G5_method, Rscratch, Gargs, false); - __ call_from_interpreter(Rscratch, Gargs, Rret); -} - - -void TemplateTable::invokestatic(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f1_byte, "use this argument"); - - const Register Rret = Lscratch; - const Register Rscratch = G3_scratch; - - prepare_invoke(byte_no, G5_method, Rret); // get f1 Method* - - // do the call - __ profile_call(O4); - __ profile_arguments_type(G5_method, Rscratch, Gargs, false); - __ call_from_interpreter(Rscratch, Gargs, Rret); -} - -void TemplateTable::invokeinterface_object_method(Register RKlass, - Register Rcall, - Register Rret, - Register Rflags) { - Register Rscratch = G4_scratch; - Register Rindex = Lscratch; - - assert_different_registers(Rscratch, Rindex, Rret); - - Label notFinal; - - // Check for vfinal - __ set((1 << ConstantPoolCacheEntry::is_vfinal_shift), Rscratch); - __ btst(Rflags, Rscratch); - __ br(Assembler::zero, false, Assembler::pt, notFinal); - __ delayed()->nop(); - - __ profile_final_call(O4); - - // do the call - the index (f2) contains the Method* - assert_different_registers(G5_method, Gargs, Rcall); - __ mov(Rindex, G5_method); - __ profile_arguments_type(G5_method, Rcall, Gargs, true); - __ call_from_interpreter(Rcall, Gargs, Rret); - __ bind(notFinal); - - __ profile_virtual_call(RKlass, O4); - generate_vtable_call(RKlass, Rindex, Rret); -} - - -void TemplateTable::invokeinterface(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f1_byte, "use this argument"); - - const Register Rinterface = G1_scratch; - const Register Rmethod = Lscratch; - const Register Rret = G3_scratch; - const Register O0_recv = O0; - const Register O1_flags = O1; - const Register O2_Klass = O2; - const Register Rscratch = G4_scratch; - assert_different_registers(Rscratch, G5_method); - - prepare_invoke(byte_no, Rinterface, Rret, Rmethod, O0_recv, O1_flags); - - // First check for Object case, then private interface method, - // then regular interface method. - - // get receiver klass - this is also a null check - __ null_check(O0_recv, oopDesc::klass_offset_in_bytes()); - __ load_klass(O0_recv, O2_Klass); - - // Special case of invokeinterface called for virtual method of - // java.lang.Object. See cpCache.cpp for details. - Label notObjectMethod; - __ set((1 << ConstantPoolCacheEntry::is_forced_virtual_shift), Rscratch); - __ btst(O1_flags, Rscratch); - __ br(Assembler::zero, false, Assembler::pt, notObjectMethod); - __ delayed()->nop(); - - invokeinterface_object_method(O2_Klass, Rinterface, Rret, O1_flags); - - __ bind(notObjectMethod); - - Label L_no_such_interface; - - // Check for private method invocation - indicated by vfinal - Label notVFinal; - { - __ set((1 << ConstantPoolCacheEntry::is_vfinal_shift), Rscratch); - __ btst(O1_flags, Rscratch); - __ br(Assembler::zero, false, Assembler::pt, notVFinal); - __ delayed()->nop(); - - Label subtype; - Register Rtemp = O1_flags; - __ check_klass_subtype(O2_Klass, Rinterface, Rscratch, Rtemp, subtype); - // If we get here the typecheck failed - __ ba(L_no_such_interface); - __ delayed()->nop(); - __ bind(subtype); - - // do the call - Register Rcall = Rinterface; - __ mov(Rmethod, G5_method); - assert_different_registers(Rcall, G5_method, Gargs, Rret); - - __ profile_arguments_type(G5_method, Rcall, Gargs, true); - __ profile_final_call(Rscratch); - __ call_from_interpreter(Rcall, Gargs, Rret); - } - __ bind(notVFinal); - - Register Rtemp = O1_flags; - - // Receiver subtype check against REFC. - __ lookup_interface_method(// inputs: rec. class, interface, itable index - O2_Klass, Rinterface, noreg, - // outputs: temp reg1, temp reg2, temp reg3 - G5_method, Rscratch, Rtemp, - L_no_such_interface, - /*return_method=*/false); - - __ profile_virtual_call(O2_Klass, O4); - - // - // find entry point to call - // - - // Get declaring interface class from method - __ ld_ptr(Rmethod, Method::const_offset(), Rinterface); - __ ld_ptr(Rinterface, ConstMethod::constants_offset(), Rinterface); - __ ld_ptr(Rinterface, ConstantPool::pool_holder_offset_in_bytes(), Rinterface); - - // Get itable index from method - const Register Rindex = G5_method; - __ ld(Rmethod, Method::itable_index_offset(), Rindex); - __ sub(Rindex, Method::itable_index_max, Rindex); - __ neg(Rindex); - - // Preserve O2_Klass for throw_AbstractMethodErrorVerbose - __ mov(O2_Klass, O4); - __ lookup_interface_method(// inputs: rec. class, interface, itable index - O4, Rinterface, Rindex, - // outputs: method, scan temp reg, temp reg - G5_method, Rscratch, Rtemp, - L_no_such_interface); - - // Check for abstract method error. - { - Label ok; - __ br_notnull_short(G5_method, Assembler::pt, ok); - // Pass arguments for generating a verbose error message. - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorVerbose), - O2_Klass, Rmethod); - __ should_not_reach_here(); - __ bind(ok); - } - - Register Rcall = Rinterface; - assert_different_registers(Rcall, G5_method, Gargs, Rret); - - __ profile_arguments_type(G5_method, Rcall, Gargs, true); - __ call_from_interpreter(Rcall, Gargs, Rret); - - __ bind(L_no_such_interface); - // Pass arguments for generating a verbose error message. - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose), - O2_Klass, Rinterface); - __ should_not_reach_here(); -} - -void TemplateTable::invokehandle(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f1_byte, "use this argument"); - - const Register Rret = Lscratch; - const Register G4_mtype = G4_scratch; - const Register O0_recv = O0; - const Register Rscratch = G3_scratch; - - prepare_invoke(byte_no, G5_method, Rret, G4_mtype, O0_recv); - __ null_check(O0_recv); - - // G4: MethodType object (from cpool->resolved_references[f1], if necessary) - // G5: MH.invokeExact_MT method (from f2) - - // Note: G4_mtype is already pushed (if necessary) by prepare_invoke - - // do the call - __ verify_oop(G4_mtype); - __ profile_final_call(O4); // FIXME: profile the LambdaForm also - __ profile_arguments_type(G5_method, Rscratch, Gargs, true); - __ call_from_interpreter(Rscratch, Gargs, Rret); -} - - -void TemplateTable::invokedynamic(int byte_no) { - transition(vtos, vtos); - assert(byte_no == f1_byte, "use this argument"); - - const Register Rret = Lscratch; - const Register G4_callsite = G4_scratch; - const Register Rscratch = G3_scratch; - - prepare_invoke(byte_no, G5_method, Rret, G4_callsite); - - // G4: CallSite object (from cpool->resolved_references[f1]) - // G5: MH.linkToCallSite method (from f2) - - // Note: G4_callsite is already pushed by prepare_invoke - - // %%% should make a type profile for any invokedynamic that takes a ref argument - // profile this call - __ profile_call(O4); - - // do the call - __ verify_oop(G4_callsite); - __ profile_arguments_type(G5_method, Rscratch, Gargs, false); - __ call_from_interpreter(Rscratch, Gargs, Rret); -} - - -//---------------------------------------------------------------------------------------------------- -// Allocation - -void TemplateTable::_new() { - transition(vtos, atos); - - Label slow_case; - Label done; - Label initialize_header; - Label initialize_object; // including clearing the fields - - Register RallocatedObject = Otos_i; - Register RinstanceKlass = O1; - Register Roffset = O3; - Register Rscratch = O4; - - __ get_2_byte_integer_at_bcp(1, Rscratch, Roffset, InterpreterMacroAssembler::Unsigned); - __ get_cpool_and_tags(Rscratch, G3_scratch); - // make sure the class we're about to instantiate has been resolved - // This is done before loading InstanceKlass to be consistent with the order - // how Constant Pool is updated (see ConstantPool::klass_at_put) - __ add(G3_scratch, Array::base_offset_in_bytes(), G3_scratch); - __ ldub(G3_scratch, Roffset, G3_scratch); - __ cmp(G3_scratch, JVM_CONSTANT_Class); - __ br(Assembler::notEqual, false, Assembler::pn, slow_case); - __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); - // get InstanceKlass - __ load_resolved_klass_at_offset(Rscratch, Roffset, RinstanceKlass); - - // make sure klass is fully initialized: - __ ldub(RinstanceKlass, in_bytes(InstanceKlass::init_state_offset()), G3_scratch); - __ cmp(G3_scratch, InstanceKlass::fully_initialized); - __ br(Assembler::notEqual, false, Assembler::pn, slow_case); - __ delayed()->ld(RinstanceKlass, in_bytes(Klass::layout_helper_offset()), Roffset); - - // get instance_size in InstanceKlass (already aligned) - //__ ld(RinstanceKlass, in_bytes(Klass::layout_helper_offset()), Roffset); - - // make sure klass does not have has_finalizer, or is abstract, or interface or java/lang/Class - __ btst(Klass::_lh_instance_slow_path_bit, Roffset); - __ br(Assembler::notZero, false, Assembler::pn, slow_case); - __ delayed()->nop(); - - // Allocate the instance: - // If TLAB is enabled: - // Try to allocate in the TLAB. - // If fails, go to the slow path. - // Else If inline contiguous allocations are enabled: - // Try to allocate in eden. - // If fails due to heap end, go to slow path. - // - // If TLAB is enabled OR inline contiguous is enabled: - // Initialize the allocation. - // Exit. - // - // Go to slow path. - - const bool allow_shared_alloc = - Universe::heap()->supports_inline_contig_alloc(); - - if(UseTLAB) { - Register RoldTopValue = RallocatedObject; - Register RtlabWasteLimitValue = G3_scratch; - Register RnewTopValue = G1_scratch; - Register RendValue = Rscratch; - Register RfreeValue = RnewTopValue; - - // check if we can allocate in the TLAB - __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), RoldTopValue); // sets up RalocatedObject - __ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), RendValue); - __ add(RoldTopValue, Roffset, RnewTopValue); - - // if there is enough space, we do not CAS and do not clear - __ cmp(RnewTopValue, RendValue); - if(ZeroTLAB) { - // the fields have already been cleared - __ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_header); - } else { - // initialize both the header and fields - __ brx(Assembler::lessEqualUnsigned, true, Assembler::pt, initialize_object); - } - __ delayed()->st_ptr(RnewTopValue, G2_thread, in_bytes(JavaThread::tlab_top_offset())); - - // Allocation does not fit in the TLAB. - __ ba_short(slow_case); - } else { - // Allocation in the shared Eden - if (allow_shared_alloc) { - Register RoldTopValue = G1_scratch; - Register RtopAddr = G3_scratch; - Register RnewTopValue = RallocatedObject; - Register RendValue = Rscratch; - - __ set((intptr_t)Universe::heap()->top_addr(), RtopAddr); - - Label retry; - __ bind(retry); - __ set((intptr_t)Universe::heap()->end_addr(), RendValue); - __ ld_ptr(RendValue, 0, RendValue); - __ ld_ptr(RtopAddr, 0, RoldTopValue); - __ add(RoldTopValue, Roffset, RnewTopValue); - - // RnewTopValue contains the top address after the new object - // has been allocated. - __ cmp_and_brx_short(RnewTopValue, RendValue, Assembler::greaterUnsigned, Assembler::pn, slow_case); - - __ cas_ptr(RtopAddr, RoldTopValue, RnewTopValue); - - // if someone beat us on the allocation, try again, otherwise continue - __ cmp_and_brx_short(RoldTopValue, RnewTopValue, Assembler::notEqual, Assembler::pn, retry); - - // bump total bytes allocated by this thread - // RoldTopValue and RtopAddr are dead, so can use G1 and G3 - __ incr_allocated_bytes(Roffset, G1_scratch, G3_scratch); - } - } - - // If UseTLAB or allow_shared_alloc are true, the object is created above and - // there is an initialize need. Otherwise, skip and go to the slow path. - if (UseTLAB || allow_shared_alloc) { - // clear object fields - __ bind(initialize_object); - __ deccc(Roffset, sizeof(oopDesc)); - __ br(Assembler::zero, false, Assembler::pt, initialize_header); - __ delayed()->add(RallocatedObject, sizeof(oopDesc), G3_scratch); - - // initialize remaining object fields - if (UseBlockZeroing) { - // Use BIS for zeroing - __ bis_zeroing(G3_scratch, Roffset, G1_scratch, initialize_header); - } else { - Label loop; - __ subcc(Roffset, wordSize, Roffset); - __ bind(loop); - //__ subcc(Roffset, wordSize, Roffset); // executed above loop or in delay slot - __ st_ptr(G0, G3_scratch, Roffset); - __ br(Assembler::notEqual, false, Assembler::pt, loop); - __ delayed()->subcc(Roffset, wordSize, Roffset); - } - __ ba_short(initialize_header); - } - - // slow case - __ bind(slow_case); - __ get_2_byte_integer_at_bcp(1, G3_scratch, O2, InterpreterMacroAssembler::Unsigned); - __ get_constant_pool(O1); - - call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), O1, O2); - - __ ba_short(done); - - // Initialize the header: mark, klass - __ bind(initialize_header); - - if (UseBiasedLocking) { - __ ld_ptr(RinstanceKlass, in_bytes(Klass::prototype_header_offset()), G4_scratch); - } else { - __ set((intptr_t)markWord::prototype().value(), G4_scratch); - } - __ st_ptr(G4_scratch, RallocatedObject, oopDesc::mark_offset_in_bytes()); // mark - __ store_klass_gap(G0, RallocatedObject); // klass gap if compressed - __ store_klass(RinstanceKlass, RallocatedObject); // klass (last for cms) - - { - SkipIfEqual skip_if( - _masm, G4_scratch, &DTraceAllocProbes, Assembler::zero); - // Trigger dtrace event - __ push(atos); - __ call_VM_leaf(noreg, - CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), O0); - __ pop(atos); - } - - // continue - __ bind(done); -} - - - -void TemplateTable::newarray() { - transition(itos, atos); - __ ldub(Lbcp, 1, O1); - call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), O1, Otos_i); -} - - -void TemplateTable::anewarray() { - transition(itos, atos); - __ get_constant_pool(O1); - __ get_2_byte_integer_at_bcp(1, G4_scratch, O2, InterpreterMacroAssembler::Unsigned); - call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), O1, O2, Otos_i); -} - - -void TemplateTable::arraylength() { - transition(atos, itos); - Label ok; - __ verify_oop(Otos_i); - __ tst(Otos_i); - __ throw_if_not_1_x( Assembler::notZero, ok ); - __ delayed()->ld(Otos_i, arrayOopDesc::length_offset_in_bytes(), Otos_i); - __ throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ok); -} - - -void TemplateTable::checkcast() { - transition(atos, atos); - Label done, is_null, quicked, cast_ok, resolved; - Register Roffset = G1_scratch; - Register RobjKlass = O5; - Register RspecifiedKlass = O4; - - // Check for casting a NULL - __ br_null(Otos_i, false, Assembler::pn, is_null); - __ delayed()->nop(); - - // Get value klass in RobjKlass - __ load_klass(Otos_i, RobjKlass); // get value klass - - // Get constant pool tag - __ get_2_byte_integer_at_bcp(1, Lscratch, Roffset, InterpreterMacroAssembler::Unsigned); - - // See if the checkcast has been quickened - __ get_cpool_and_tags(Lscratch, G3_scratch); - __ add(G3_scratch, Array::base_offset_in_bytes(), G3_scratch); - __ ldub(G3_scratch, Roffset, G3_scratch); - __ cmp(G3_scratch, JVM_CONSTANT_Class); - __ br(Assembler::equal, true, Assembler::pt, quicked); - __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); - - __ push_ptr(); // save receiver for result, and for GC - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) ); - __ get_vm_result_2(RspecifiedKlass); - __ pop_ptr(Otos_i, G3_scratch); // restore receiver - - __ ba_short(resolved); - - // Extract target class from constant pool - __ bind(quicked); - __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass); - - - __ bind(resolved); - __ load_klass(Otos_i, RobjKlass); // get value klass - - // Generate a fast subtype check. Branch to cast_ok if no - // failure. Throw exception if failure. - __ gen_subtype_check( RobjKlass, RspecifiedKlass, G3_scratch, G4_scratch, G1_scratch, cast_ok ); - - // Not a subtype; so must throw exception - __ throw_if_not_x( Assembler::never, Interpreter::_throw_ClassCastException_entry, G3_scratch ); - - __ bind(cast_ok); - - if (ProfileInterpreter) { - __ ba_short(done); - } - __ bind(is_null); - __ profile_null_seen(G3_scratch); - __ bind(done); -} - - -void TemplateTable::instanceof() { - Label done, is_null, quicked, resolved; - transition(atos, itos); - Register Roffset = G1_scratch; - Register RobjKlass = O5; - Register RspecifiedKlass = O4; - - // Check for casting a NULL - __ br_null(Otos_i, false, Assembler::pt, is_null); - __ delayed()->nop(); - - // Get value klass in RobjKlass - __ load_klass(Otos_i, RobjKlass); // get value klass - - // Get constant pool tag - __ get_2_byte_integer_at_bcp(1, Lscratch, Roffset, InterpreterMacroAssembler::Unsigned); - - // See if the checkcast has been quickened - __ get_cpool_and_tags(Lscratch, G3_scratch); - __ add(G3_scratch, Array::base_offset_in_bytes(), G3_scratch); - __ ldub(G3_scratch, Roffset, G3_scratch); - __ cmp(G3_scratch, JVM_CONSTANT_Class); - __ br(Assembler::equal, true, Assembler::pt, quicked); - __ delayed()->sll(Roffset, LogBytesPerWord, Roffset); - - __ push_ptr(); // save receiver for result, and for GC - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc) ); - __ get_vm_result_2(RspecifiedKlass); - __ pop_ptr(Otos_i, G3_scratch); // restore receiver - - __ ba_short(resolved); - - // Extract target class from constant pool - __ bind(quicked); - __ get_constant_pool(Lscratch); - __ load_resolved_klass_at_offset(Lscratch, Roffset, RspecifiedKlass); - - __ bind(resolved); - __ load_klass(Otos_i, RobjKlass); // get value klass - - // Generate a fast subtype check. Branch to cast_ok if no - // failure. Return 0 if failure. - __ or3(G0, 1, Otos_i); // set result assuming quick tests succeed - __ gen_subtype_check( RobjKlass, RspecifiedKlass, G3_scratch, G4_scratch, G1_scratch, done ); - // Not a subtype; return 0; - __ clr( Otos_i ); - - if (ProfileInterpreter) { - __ ba_short(done); - } - __ bind(is_null); - __ profile_null_seen(G3_scratch); - __ bind(done); -} - -void TemplateTable::_breakpoint() { - - // Note: We get here even if we are single stepping.. - // jbug insists on setting breakpoints at every bytecode - // even if we are in single step mode. - - transition(vtos, vtos); - // get the unpatched byte code - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::get_original_bytecode_at), Lmethod, Lbcp); - __ mov(O0, Lbyte_code); - - // post the breakpoint event - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), Lmethod, Lbcp); - - // complete the execution of original bytecode - __ dispatch_normal(vtos); -} - - -//---------------------------------------------------------------------------------------------------- -// Exceptions - -void TemplateTable::athrow() { - transition(atos, vtos); - - // This works because exception is cached in Otos_i which is same as O0, - // which is same as what throw_exception_entry_expects - assert(Otos_i == Oexception, "see explanation above"); - - __ verify_oop(Otos_i); - __ null_check(Otos_i); - __ throw_if_not_x(Assembler::never, Interpreter::throw_exception_entry(), G3_scratch); -} - - -//---------------------------------------------------------------------------------------------------- -// Synchronization - - -// See frame_sparc.hpp for monitor block layout. -// Monitor elements are dynamically allocated by growing stack as needed. - -void TemplateTable::monitorenter() { - transition(atos, vtos); - __ verify_oop(Otos_i); - // Try to acquire a lock on the object - // Repeat until succeeded (i.e., until - // monitorenter returns true). - - { Label ok; - __ tst(Otos_i); - __ throw_if_not_1_x( Assembler::notZero, ok); - __ delayed()->mov(Otos_i, Lscratch); // save obj - __ throw_if_not_2( Interpreter::_throw_NullPointerException_entry, G3_scratch, ok); - } - - assert(O0 == Otos_i, "Be sure where the object to lock is"); - - // find a free slot in the monitor block - - - // initialize entry pointer - __ clr(O1); // points to free slot or NULL - - { - Label entry, loop, exit; - __ add( __ top_most_monitor(), O2 ); // last one to check - __ ba( entry ); - __ delayed()->mov( Lmonitors, O3 ); // first one to check - - - __ bind( loop ); - - __ verify_oop(O4); // verify each monitor's oop - __ tst(O4); // is this entry unused? - __ movcc( Assembler::zero, false, Assembler::ptr_cc, O3, O1); - - __ cmp(O4, O0); // check if current entry is for same object - __ brx( Assembler::equal, false, Assembler::pn, exit ); - __ delayed()->inc( O3, frame::interpreter_frame_monitor_size() * wordSize ); // check next one - - __ bind( entry ); - - __ cmp( O3, O2 ); - __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, loop ); - __ delayed()->ld_ptr(O3, BasicObjectLock::obj_offset_in_bytes(), O4); - - __ bind( exit ); - } - - { Label allocated; - - // found free slot? - __ br_notnull_short(O1, Assembler::pn, allocated); - - __ add_monitor_to_stack( false, O2, O3 ); - __ mov(Lmonitors, O1); - - __ bind(allocated); - } - - // Increment bcp to point to the next bytecode, so exception handling for async. exceptions work correctly. - // The object has already been poped from the stack, so the expression stack looks correct. - __ inc(Lbcp); - - __ st_ptr(O0, O1, BasicObjectLock::obj_offset_in_bytes()); // store object - __ lock_object(O1, O0); - - // check if there's enough space on the stack for the monitors after locking - __ generate_stack_overflow_check(0); - - // The bcp has already been incremented. Just need to dispatch to next instruction. - __ dispatch_next(vtos); -} - - -void TemplateTable::monitorexit() { - transition(atos, vtos); - __ verify_oop(Otos_i); - __ tst(Otos_i); - __ throw_if_not_x( Assembler::notZero, Interpreter::_throw_NullPointerException_entry, G3_scratch ); - - assert(O0 == Otos_i, "just checking"); - - { Label entry, loop, found; - __ add( __ top_most_monitor(), O2 ); // last one to check - __ ba(entry); - // use Lscratch to hold monitor elem to check, start with most recent monitor, - // By using a local it survives the call to the C routine. - __ delayed()->mov( Lmonitors, Lscratch ); - - __ bind( loop ); - - __ verify_oop(O4); // verify each monitor's oop - __ cmp(O4, O0); // check if current entry is for desired object - __ brx( Assembler::equal, true, Assembler::pt, found ); - __ delayed()->mov(Lscratch, O1); // pass found entry as argument to monitorexit - - __ inc( Lscratch, frame::interpreter_frame_monitor_size() * wordSize ); // advance to next - - __ bind( entry ); - - __ cmp( Lscratch, O2 ); - __ brx( Assembler::lessEqualUnsigned, true, Assembler::pt, loop ); - __ delayed()->ld_ptr(Lscratch, BasicObjectLock::obj_offset_in_bytes(), O4); - - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception)); - __ should_not_reach_here(); - - __ bind(found); - } - __ unlock_object(O1); -} - - -//---------------------------------------------------------------------------------------------------- -// Wide instructions - -void TemplateTable::wide() { - transition(vtos, vtos); - __ ldub(Lbcp, 1, G3_scratch);// get next bc - __ sll(G3_scratch, LogBytesPerWord, G3_scratch); - AddressLiteral ep(Interpreter::_wentry_point); - __ set(ep, G4_scratch); - __ ld_ptr(G4_scratch, G3_scratch, G3_scratch); - __ jmp(G3_scratch, G0); - __ delayed()->nop(); - // Note: the Lbcp increment step is part of the individual wide bytecode implementations -} - - -//---------------------------------------------------------------------------------------------------- -// Multi arrays - -void TemplateTable::multianewarray() { - transition(vtos, atos); - // put ndims * wordSize into Lscratch - __ ldub( Lbcp, 3, Lscratch); - __ sll( Lscratch, Interpreter::logStackElementSize, Lscratch); - // Lesp points past last_dim, so set to O1 to first_dim address - __ add( Lesp, Lscratch, O1); - call_VM(Otos_i, CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), O1); - __ add( Lesp, Lscratch, Lesp); // pop all dimensions off the stack -} diff --git a/src/hotspot/cpu/sparc/templateTable_sparc.hpp b/src/hotspot/cpu/sparc/templateTable_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/templateTable_sparc.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef CPU_SPARC_TEMPLATETABLE_SPARC_HPP -#define CPU_SPARC_TEMPLATETABLE_SPARC_HPP - - static void prepare_invoke(int byte_no, - Register method, // linked method (or i-klass) - Register ra, // return address - 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 - ); - // helper function - static void invokevfinal_helper(Register Rcache, Register Rret); - static void invokeinterface_object_method(Register RKlass, Register Rcall, - Register Rret, - Register Rflags); - static void generate_vtable_call(Register Rrecv, Register Rindex, Register Rret); - static void volatile_barrier(Assembler::Membar_mask_bits order_constraint); - -#endif // CPU_SPARC_TEMPLATETABLE_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/vmStructs_sparc.hpp b/src/hotspot/cpu/sparc/vmStructs_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vmStructs_sparc.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2001, 2019, 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. - * - */ - -#ifndef CPU_SPARC_VMSTRUCTS_SPARC_HPP -#define CPU_SPARC_VMSTRUCTS_SPARC_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) \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) - -#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) \ - /******************************/ \ - /* Register numbers (C2 only) */ \ - /******************************/ \ - \ - declare_c2_constant(R_L0_num) \ - declare_c2_constant(R_L1_num) \ - declare_c2_constant(R_L2_num) \ - declare_c2_constant(R_L3_num) \ - declare_c2_constant(R_L4_num) \ - declare_c2_constant(R_L5_num) \ - declare_c2_constant(R_L6_num) \ - declare_c2_constant(R_L7_num) \ - declare_c2_constant(R_I0_num) \ - declare_c2_constant(R_I1_num) \ - declare_c2_constant(R_I2_num) \ - declare_c2_constant(R_I3_num) \ - declare_c2_constant(R_I4_num) \ - declare_c2_constant(R_I5_num) \ - declare_c2_constant(R_FP_num) \ - declare_c2_constant(R_I7_num) \ - declare_c2_constant(R_O0_num) \ - declare_c2_constant(R_O1_num) \ - declare_c2_constant(R_O2_num) \ - declare_c2_constant(R_O3_num) \ - declare_c2_constant(R_O4_num) \ - declare_c2_constant(R_O5_num) \ - declare_c2_constant(R_SP_num) \ - declare_c2_constant(R_O7_num) \ - declare_c2_constant(R_G0_num) \ - declare_c2_constant(R_G1_num) \ - declare_c2_constant(R_G2_num) \ - declare_c2_constant(R_G3_num) \ - declare_c2_constant(R_G4_num) \ - declare_c2_constant(R_G5_num) \ - declare_c2_constant(R_G6_num) \ - declare_c2_constant(R_G7_num) \ - declare_constant(VM_Version::ISA_V9) \ - declare_constant(VM_Version::ISA_POPC) \ - declare_constant(VM_Version::ISA_VIS1) \ - declare_constant(VM_Version::ISA_VIS2) \ - declare_constant(VM_Version::ISA_BLK_INIT) \ - declare_constant(VM_Version::ISA_FMAF) \ - declare_constant(VM_Version::ISA_VIS3) \ - declare_constant(VM_Version::ISA_HPC) \ - declare_constant(VM_Version::ISA_IMA) \ - declare_constant(VM_Version::ISA_AES) \ - declare_constant(VM_Version::ISA_DES) \ - declare_constant(VM_Version::ISA_KASUMI) \ - declare_constant(VM_Version::ISA_CAMELLIA) \ - declare_constant(VM_Version::ISA_MD5) \ - declare_constant(VM_Version::ISA_SHA1) \ - declare_constant(VM_Version::ISA_SHA256) \ - declare_constant(VM_Version::ISA_SHA512) \ - declare_constant(VM_Version::ISA_MPMUL) \ - declare_constant(VM_Version::ISA_MONT) \ - declare_constant(VM_Version::ISA_PAUSE) \ - declare_constant(VM_Version::ISA_CBCOND) \ - declare_constant(VM_Version::ISA_CRC32C) \ - declare_constant(VM_Version::ISA_VIS3B) \ - declare_constant(VM_Version::ISA_ADI) \ - declare_constant(VM_Version::ISA_SPARC5) \ - declare_constant(VM_Version::ISA_MWAIT) \ - declare_constant(VM_Version::ISA_XMPMUL) \ - declare_constant(VM_Version::ISA_XMONT) \ - declare_constant(VM_Version::ISA_PAUSE_NSEC) \ - declare_constant(VM_Version::ISA_VAMASK) \ - declare_constant(VM_Version::ISA_SPARC6) \ - declare_constant(VM_Version::ISA_DICTUNP) \ - declare_constant(VM_Version::ISA_FPCMPSHL) \ - declare_constant(VM_Version::ISA_RLE) \ - declare_constant(VM_Version::ISA_SHA3) \ - declare_constant(VM_Version::ISA_VIS3C) \ - declare_constant(VM_Version::ISA_SPARC5B) \ - declare_constant(VM_Version::ISA_MME) \ - declare_constant(VM_Version::CPU_FAST_IDIV) \ - declare_constant(VM_Version::CPU_FAST_RDPC) \ - declare_constant(VM_Version::CPU_FAST_BIS) \ - declare_constant(VM_Version::CPU_FAST_LD) \ - declare_constant(VM_Version::CPU_FAST_CMOVE) \ - declare_constant(VM_Version::CPU_FAST_IND_BR) \ - declare_constant(VM_Version::CPU_BLK_ZEROING) - -#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#endif // CPU_SPARC_VMSTRUCTS_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp b/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vm_version_ext_sparc.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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. - * - */ - -#include "jvm.h" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "vm_version_ext_sparc.hpp" - -// VM_Version_Ext statics -int VM_Version_Ext::_no_of_threads = 0; -int VM_Version_Ext::_no_of_cores = 0; -int VM_Version_Ext::_no_of_sockets = 0; -#if defined(SOLARIS) -kid_t VM_Version_Ext::_kcid = -1; -#endif -char VM_Version_Ext::_cpu_name[CPU_TYPE_DESC_BUF_SIZE] = {0}; -char VM_Version_Ext::_cpu_desc[CPU_DETAILED_DESC_BUF_SIZE] = {0}; - -#if defined(SOLARIS) -// get cpu information. It takes into account if the kstat chain id -// has been changed and update the info if necessary. -bool VM_Version_Ext::initialize_cpu_information(void) { - - int core_id = -1; - int chip_id = -1; - int len = 0; - char* src_string = NULL; - kstat_ctl_t* kc = kstat_open(); - if (!kc) { - return false; - } - - // check if kstat chain has been updated - kid_t kcid = kstat_chain_update(kc); - if (kcid == -1) { - kstat_close(kc); - return false; - } - - bool updated = ((kcid > 0) && (kcid != _kcid)) || - ((kcid == 0) && (_kcid == -1)); - if (!updated) { - kstat_close(kc); - return true; - } - - // update the cached _kcid - _kcid = kcid; - - // find the number of online processors - // for modern processsors, it is also known as the - // hardware threads. - _no_of_threads = sysconf(_SC_NPROCESSORS_ONLN); - - if (_no_of_threads <= 0 ) { - kstat_close(kc); - return false; - } - - _no_of_cores = 0; - _no_of_sockets = 0; - - // loop through the kstat chain - kstat_t* ksp = NULL; - for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { - // only interested in "cpu_info" - if (strcmp(ksp->ks_module, (char*)CPU_INFO) == 0) { - if (kstat_read(kc, ksp, NULL) == -1) { - kstat_close(kc); - return false; - } - if (ksp->ks_data != NULL) { - kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; - // loop through the number of fields in each record - for (int i = 0; i < ksp->ks_ndata; i++) { - // set cpu type if it hasn't been already set - if ((strcmp((const char*)&(knm[i].name), CPU_TYPE) == 0) && - (_cpu_name[0] == '\0')) { - if (knm[i].data_type == KSTAT_DATA_STRING) { - src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]); - } else { - src_string = (char*)&(knm[i].value.c[0]); - } - len = strlen(src_string); - if (len < CPU_TYPE_DESC_BUF_SIZE) { - jio_snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE, - "%s", src_string); - } - } - - // set cpu description if it hasn't been already set - if ((strcmp((const char*)&(knm[i].name), CPU_DESCRIPTION) == 0) && - (_cpu_desc[0] == '\0')) { - if (knm[i].data_type == KSTAT_DATA_STRING) { - src_string = (char*)KSTAT_NAMED_STR_PTR(&knm[i]); - } else { - src_string = (char*)&(knm[i].value.c[0]); - } - len = strlen(src_string); - if (len < CPU_DETAILED_DESC_BUF_SIZE) { - jio_snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, - "%s", src_string); - } - } - - // count the number of sockets based on the chip id - if (strcmp((const char*)&(knm[i].name), CHIP_ID) == 0) { - if (chip_id != knm[i].value.l) { - chip_id = knm[i].value.l; - _no_of_sockets++; - } - } - - // count the number of cores based on the core id - if (strcmp((const char*)&(knm[i].name), CORE_ID) == 0) { - if (core_id != knm[i].value.l) { - core_id = knm[i].value.l; - _no_of_cores++; - } - } - } - } - } - } - - kstat_close(kc); - return true; -} -#elif defined(LINUX) -// get cpu information. -bool VM_Version_Ext::initialize_cpu_information(void) { - // Not yet implemented. - return false; -} -#endif - -int VM_Version_Ext::number_of_threads(void) { - initialize_cpu_information(); - return _no_of_threads; -} - -int VM_Version_Ext::number_of_cores(void) { - initialize_cpu_information(); - return _no_of_cores; -} - -int VM_Version_Ext::number_of_sockets(void) { - initialize_cpu_information(); - return _no_of_sockets; -} - -const char* VM_Version_Ext::cpu_name(void) { - if (!initialize_cpu_information()) { - return NULL; - } - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_TYPE_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_name, CPU_TYPE_DESC_BUF_SIZE); - return tmp; -} - -const char* VM_Version_Ext::cpu_description(void) { - if (!initialize_cpu_information()) { - return NULL; - } - char* tmp = NEW_C_HEAP_ARRAY_RETURN_NULL(char, CPU_DETAILED_DESC_BUF_SIZE, mtTracing); - if (NULL == tmp) { - return NULL; - } - strncpy(tmp, _cpu_desc, CPU_DETAILED_DESC_BUF_SIZE); - return tmp; -} diff --git a/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp b/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vm_version_ext_sparc.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2013, 2019, 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. - * - */ - -#ifndef CPU_SPARC_VM_VERSION_EXT_SPARC_HPP -#define CPU_SPARC_VM_VERSION_EXT_SPARC_HPP - -#include "runtime/vm_version.hpp" -#include "utilities/macros.hpp" - -#if defined(SOLARIS) -#include -#include -#endif - -#define CPU_INFO "cpu_info" -#define CPU_TYPE "fpu_type" -#define CPU_DESCRIPTION "implementation" -#define CHIP_ID "chip_id" -#define CORE_ID "core_id" - -class VM_Version_Ext : public VM_Version { - private: - - static const size_t CPU_TYPE_DESC_BUF_SIZE = 256; - static const size_t CPU_DETAILED_DESC_BUF_SIZE = 4096; - - static int _no_of_threads; - static int _no_of_cores; - static int _no_of_sockets; -#if defined(SOLARIS) - static kid_t _kcid; -#endif - static char _cpu_name[CPU_TYPE_DESC_BUF_SIZE]; - static char _cpu_desc[CPU_DETAILED_DESC_BUF_SIZE]; - - static bool initialize_cpu_information(void); - - public: - - static int number_of_threads(void); - static int number_of_cores(void); - static int number_of_sockets(void); - - static const char* cpu_name(void); - static const char* cpu_description(void); -}; - -#endif // CPU_SPARC_VM_VERSION_EXT_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/vm_version_sparc.cpp b/src/hotspot/cpu/sparc/vm_version_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vm_version_sparc.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "jvm.h" -#include "asm/macroAssembler.inline.hpp" -#include "logging/log.hpp" -#include "logging/logStream.hpp" -#include "memory/resourceArea.hpp" -#include "oops/compressedOops.hpp" -#include "runtime/java.hpp" -#include "runtime/os.hpp" -#include "runtime/stubCodeGenerator.hpp" -#include "runtime/vm_version.hpp" - -#include - -uint VM_Version::_L2_data_cache_line_size = 0; - -void VM_Version::initialize() { - assert(_features != 0, "System pre-initialization is not complete."); - guarantee(VM_Version::has_v9(), "only SPARC v9 is supported"); - - PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes(); - PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes(); - PrefetchFieldsAhead = prefetch_fields_ahead(); - - // Allocation prefetch settings - - AllocatePrefetchDistance = allocate_prefetch_distance(); - AllocatePrefetchStyle = allocate_prefetch_style(); - - intx cache_line_size = prefetch_data_size(); - - if (FLAG_IS_DEFAULT(AllocatePrefetchStepSize)) { - AllocatePrefetchStepSize = MAX2(AllocatePrefetchStepSize, cache_line_size); - } - - if (AllocatePrefetchInstr == 1) { - if (!has_blk_init()) { - warning("BIS instructions required for AllocatePrefetchInstr 1 unavailable"); - FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0); - } - if (cache_line_size <= 0) { - warning("Cache-line size must be known for AllocatePrefetchInstr 1 to work"); - FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0); - } - } - - _supports_cx8 = true; // All SPARC V9 implementations. - _supports_atomic_getset4 = true; // Using the 'swap' instruction. - - if (has_fast_ind_br() && FLAG_IS_DEFAULT(UseInlineCaches)) { - // Indirect and direct branches are cost equivalent. - FLAG_SET_DEFAULT(UseInlineCaches, false); - } - // Align loops on the proper instruction boundary to fill the instruction - // fetch buffer. - if (FLAG_IS_DEFAULT(OptoLoopAlignment)) { - FLAG_SET_DEFAULT(OptoLoopAlignment, VM_Version::insn_fetch_alignment); - } - - // 32-bit oops don't make sense for the 64-bit VM on SPARC since the 32-bit - // VM has the same registers and smaller objects. - CompressedOops::set_shift(LogMinObjAlignmentInBytes); - CompressedKlassPointers::set_shift(LogKlassAlignmentInBytes); - -#ifdef COMPILER2 - if (has_fast_ind_br() && FLAG_IS_DEFAULT(UseJumpTables)) { - // Indirect and direct branches are cost equivalent. - FLAG_SET_DEFAULT(UseJumpTables, true); - } - // Entry and loop tops are aligned to fill the instruction fetch buffer. - if (FLAG_IS_DEFAULT(InteriorEntryAlignment)) { - FLAG_SET_DEFAULT(InteriorEntryAlignment, VM_Version::insn_fetch_alignment); - } - if (UseTLAB && cache_line_size > 0 && - FLAG_IS_DEFAULT(AllocatePrefetchInstr)) { - if (has_fast_bis()) { - // Use BIS instruction for TLAB allocation prefetch. - FLAG_SET_DEFAULT(AllocatePrefetchInstr, 1); - } - else if (has_sparc5()) { - // Use prefetch instruction to avoid partial RAW issue on Core C4 processors, - // also use prefetch style 3. - FLAG_SET_DEFAULT(AllocatePrefetchInstr, 0); - if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { - FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3); - } - } - } - if (AllocatePrefetchInstr == 1) { - // Use allocation prefetch style 3 because BIS instructions require - // aligned memory addresses. - FLAG_SET_DEFAULT(AllocatePrefetchStyle, 3); - } - if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { - if (AllocatePrefetchInstr == 0) { - // Use different prefetch distance without BIS - FLAG_SET_DEFAULT(AllocatePrefetchDistance, 256); - } else { - // Use smaller prefetch distance with BIS - FLAG_SET_DEFAULT(AllocatePrefetchDistance, 64); - } - } - - // We increase the number of prefetched cache lines, to use just a bit more - // aggressive approach, when the L2-cache line size is small (32 bytes), or - // when running on newer processor implementations, such as the Core C4. - bool inc_prefetch = cache_line_size > 0 && (cache_line_size < 64 || has_sparc5()); - - if (inc_prefetch) { - // We use a factor two for small cache line sizes (as before) but a slightly - // more conservative increase when running on more recent hardware that will - // benefit from just a bit more aggressive prefetching. - if (FLAG_IS_DEFAULT(AllocatePrefetchLines)) { - const int ap_lns = AllocatePrefetchLines; - const int ap_inc = cache_line_size < 64 ? ap_lns : (ap_lns + 1) / 2; - FLAG_SET_ERGO(AllocatePrefetchLines, ap_lns + ap_inc); - } - if (FLAG_IS_DEFAULT(AllocateInstancePrefetchLines)) { - const int ip_lns = AllocateInstancePrefetchLines; - const int ip_inc = cache_line_size < 64 ? ip_lns : (ip_lns + 1) / 2; - FLAG_SET_ERGO(AllocateInstancePrefetchLines, ip_lns + ip_inc); - } - } -#endif /* COMPILER2 */ - - // Use hardware population count instruction if available. - if (has_popc()) { - if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { - FLAG_SET_DEFAULT(UsePopCountInstruction, true); - } - } else if (UsePopCountInstruction) { - warning("POPC instruction is not available on this CPU"); - FLAG_SET_DEFAULT(UsePopCountInstruction, false); - } - - // Use compare and branch instructions if available. - if (has_cbcond()) { - if (FLAG_IS_DEFAULT(UseCBCond)) { - FLAG_SET_DEFAULT(UseCBCond, true); - } - } else if (UseCBCond) { - warning("CBCOND instruction is not available on this CPU"); - FLAG_SET_DEFAULT(UseCBCond, false); - } - - // Use 'mpmul' instruction if available. - if (has_mpmul()) { - if (FLAG_IS_DEFAULT(UseMPMUL)) { - FLAG_SET_DEFAULT(UseMPMUL, true); - } - } else if (UseMPMUL) { - warning("MPMUL instruction is not available on this CPU"); - FLAG_SET_DEFAULT(UseMPMUL, false); - } - - assert(BlockZeroingLowLimit > 0, "invalid value"); - - if (has_blk_zeroing() && cache_line_size > 0) { - if (FLAG_IS_DEFAULT(UseBlockZeroing)) { - FLAG_SET_DEFAULT(UseBlockZeroing, true); - } - } else if (UseBlockZeroing) { - warning("BIS zeroing instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseBlockZeroing, false); - } - - assert(BlockCopyLowLimit > 0, "invalid value"); - - if (has_blk_zeroing() && cache_line_size > 0) { - if (FLAG_IS_DEFAULT(UseBlockCopy)) { - FLAG_SET_DEFAULT(UseBlockCopy, true); - } - } else if (UseBlockCopy) { - warning("BIS instructions are not available or expensive on this CPU"); - FLAG_SET_DEFAULT(UseBlockCopy, false); - } - -#ifdef COMPILER2 - if (has_fast_rdpc() && FLAG_IS_DEFAULT(UseRDPCForConstantTableBase)) { - FLAG_SET_DEFAULT(UseRDPCForConstantTableBase, true); - } - - // Currently not supported anywhere. - FLAG_SET_DEFAULT(UseFPUForSpilling, false); - - MaxVectorSize = 8; - - assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); -#endif - - assert((CodeEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); - assert((OptoLoopAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); - - char buf[512]; - jio_snprintf(buf, sizeof(buf), - "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s%s%s" "%s%s%s%s%s%s%s%s%s" - "%s%s%s%s%s%s%s", - (has_v9() ? "v9" : ""), - (has_popc() ? ", popc" : ""), - (has_vis1() ? ", vis1" : ""), - (has_vis2() ? ", vis2" : ""), - (has_blk_init() ? ", blk_init" : ""), - (has_fmaf() ? ", fmaf" : ""), - (has_hpc() ? ", hpc" : ""), - (has_ima() ? ", ima" : ""), - (has_aes() ? ", aes" : ""), - (has_des() ? ", des" : ""), - (has_kasumi() ? ", kas" : ""), - (has_camellia() ? ", cam" : ""), - (has_md5() ? ", md5" : ""), - (has_sha1() ? ", sha1" : ""), - (has_sha256() ? ", sha256" : ""), - (has_sha512() ? ", sha512" : ""), - (has_mpmul() ? ", mpmul" : ""), - (has_mont() ? ", mont" : ""), - (has_pause() ? ", pause" : ""), - (has_cbcond() ? ", cbcond" : ""), - (has_crc32c() ? ", crc32c" : ""), - - (has_athena_plus() ? ", athena_plus" : ""), - (has_vis3b() ? ", vis3b" : ""), - (has_adi() ? ", adi" : ""), - (has_sparc5() ? ", sparc5" : ""), - (has_mwait() ? ", mwait" : ""), - (has_xmpmul() ? ", xmpmul" : ""), - (has_xmont() ? ", xmont" : ""), - (has_pause_nsec() ? ", pause_nsec" : ""), - (has_vamask() ? ", vamask" : ""), - - (has_sparc6() ? ", sparc6" : ""), - (has_dictunp() ? ", dictunp" : ""), - (has_fpcmpshl() ? ", fpcmpshl" : ""), - (has_rle() ? ", rle" : ""), - (has_sha3() ? ", sha3" : ""), - (has_athena_plus2()? ", athena_plus2" : ""), - (has_vis3c() ? ", vis3c" : ""), - (has_sparc5b() ? ", sparc5b" : ""), - (has_mme() ? ", mme" : ""), - - (has_fast_idiv() ? ", *idiv" : ""), - (has_fast_rdpc() ? ", *rdpc" : ""), - (has_fast_bis() ? ", *bis" : ""), - (has_fast_ld() ? ", *ld" : ""), - (has_fast_cmove() ? ", *cmove" : ""), - (has_fast_ind_br() ? ", *ind_br" : ""), - (has_blk_zeroing() ? ", *blk_zeroing" : "")); - - assert(strlen(buf) >= 2, "must be"); - - _features_string = os::strdup(buf); - - log_info(os, cpu)("SPARC features detected: %s", _features_string); - - // UseVIS is set to the smallest of what hardware supports and what the command - // line requires, i.e. you cannot set UseVIS to 3 on older UltraSparc which do - // not support it. - - if (UseVIS > 3) UseVIS = 3; - if (UseVIS < 0) UseVIS = 0; - if (!has_vis3()) // Drop to 2 if no VIS3 support - UseVIS = MIN2((intx)2, UseVIS); - if (!has_vis2()) // Drop to 1 if no VIS2 support - UseVIS = MIN2((intx)1, UseVIS); - if (!has_vis1()) // Drop to 0 if no VIS1 support - UseVIS = 0; - - if (has_aes()) { - if (FLAG_IS_DEFAULT(UseAES)) { - FLAG_SET_DEFAULT(UseAES, true); - } - if (!UseAES) { - if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled."); - } - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } else { - // The AES intrinsic stubs require AES instruction support (of course) - // but also require VIS3 mode or higher for instructions it use. - if (UseVIS > 2) { - if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { - FLAG_SET_DEFAULT(UseAESIntrinsics, true); - } - } else { - if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("SPARC AES intrinsics require VIS3 instructions. Intrinsics will be disabled."); - } - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } - } - } else if (UseAES || UseAESIntrinsics) { - if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { - warning("AES instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseAES, false); - } - if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { - warning("AES intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESIntrinsics, false); - } - } - - if (UseAESCTRIntrinsics) { - warning("AES/CTR intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); - } - - // GHASH/GCM intrinsics - if (has_vis3() && (UseVIS > 2)) { - if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { - UseGHASHIntrinsics = true; - } - } else if (UseGHASHIntrinsics) { - if (!FLAG_IS_DEFAULT(UseGHASHIntrinsics)) - warning("GHASH intrinsics require VIS3 instruction support. Intrinsics will be disabled"); - FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); - } - - if (has_fmaf()) { - if (FLAG_IS_DEFAULT(UseFMA)) { - UseFMA = true; - } - } else if (UseFMA) { - warning("FMA instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseFMA, false); - } - - // SHA1, SHA256, and SHA512 instructions were added to SPARC at different times - if (has_sha1() || has_sha256() || has_sha512()) { - if (UseVIS > 0) { // SHA intrinsics use VIS1 instructions - if (FLAG_IS_DEFAULT(UseSHA)) { - FLAG_SET_DEFAULT(UseSHA, true); - } - } else { - if (UseSHA) { - warning("SPARC SHA intrinsics require VIS1 instruction support. Intrinsics will be disabled."); - FLAG_SET_DEFAULT(UseSHA, false); - } - } - } else if (UseSHA) { - warning("SHA instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseSHA, false); - } - - if (UseSHA && has_sha1()) { - if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA1Intrinsics, true); - } - } else if (UseSHA1Intrinsics) { - warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); - } - - if (UseSHA && has_sha256()) { - if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); - } - } else if (UseSHA256Intrinsics) { - warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); - } - - if (UseSHA && has_sha512()) { - if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); - } - } else if (UseSHA512Intrinsics) { - warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); - FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); - } - - if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) { - FLAG_SET_DEFAULT(UseSHA, false); - } - - if (has_crc32c()) { - if (UseVIS > 2) { // CRC32C intrinsics use VIS3 instructions - if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { - FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true); - } - } else { - if (UseCRC32CIntrinsics) { - warning("SPARC CRC32C intrinsics require VIS3 instruction support. Intrinsics will be disabled."); - FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); - } - } - } else if (UseCRC32CIntrinsics) { - warning("CRC32C instruction is not available on this CPU"); - FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); - } - - if (UseVIS > 2) { - if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { - FLAG_SET_DEFAULT(UseAdler32Intrinsics, true); - } - } else if (UseAdler32Intrinsics) { - warning("SPARC Adler32 intrinsics require VIS3 instruction support. Intrinsics will be disabled."); - FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); - } - - if (UseVIS > 2) { - if (FLAG_IS_DEFAULT(UseCRC32Intrinsics)) { - FLAG_SET_DEFAULT(UseCRC32Intrinsics, true); - } - } else if (UseCRC32Intrinsics) { - warning("SPARC CRC32 intrinsics require VIS3 instructions support. Intrinsics will be disabled"); - FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); - } - - if (UseVIS > 2) { - if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { - FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); - } - } else if (UseMultiplyToLenIntrinsic) { - warning("SPARC multiplyToLen intrinsics require VIS3 instructions support. Intrinsics will be disabled"); - FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false); - } - - if (UseVectorizedMismatchIntrinsic) { - warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); - FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); - } - - if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && - (cache_line_size > ContendedPaddingWidth)) - ContendedPaddingWidth = cache_line_size; - - // This machine does not allow unaligned memory accesses - if (UseUnalignedAccesses) { - if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) - warning("Unaligned memory access is not available on this CPU"); - FLAG_SET_DEFAULT(UseUnalignedAccesses, false); - } - - if (log_is_enabled(Info, os, cpu)) { - ResourceMark rm; - LogStream ls(Log(os, cpu)::info()); - outputStream* log = &ls; - log->print_cr("L1 data cache line size: %u", L1_data_cache_line_size()); - log->print_cr("L2 data cache line size: %u", L2_data_cache_line_size()); - log->print("Allocation"); - if (AllocatePrefetchStyle <= 0) { - log->print(": no prefetching"); - } else { - log->print(" prefetching: "); - if (AllocatePrefetchInstr == 0) { - log->print("PREFETCH"); - } else if (AllocatePrefetchInstr == 1) { - log->print("BIS"); - } - if (AllocatePrefetchLines > 1) { - log->print_cr(" at distance %d, %d lines of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchLines, (int) AllocatePrefetchStepSize); - } else { - log->print_cr(" at distance %d, one line of %d bytes", (int) AllocatePrefetchDistance, (int) AllocatePrefetchStepSize); - } - } - if (PrefetchCopyIntervalInBytes > 0) { - log->print_cr("PrefetchCopyIntervalInBytes %d", (int) PrefetchCopyIntervalInBytes); - } - if (PrefetchScanIntervalInBytes > 0) { - log->print_cr("PrefetchScanIntervalInBytes %d", (int) PrefetchScanIntervalInBytes); - } - if (PrefetchFieldsAhead > 0) { - log->print_cr("PrefetchFieldsAhead %d", (int) PrefetchFieldsAhead); - } - if (ContendedPaddingWidth > 0) { - log->print_cr("ContendedPaddingWidth %d", (int) ContendedPaddingWidth); - } - } -} - -void VM_Version::print_features() { - tty->print("ISA features [0x%0" PRIx64 "]:", _features); - if (_features_string != NULL) { - tty->print(" %s", _features_string); - } - tty->cr(); -} - -void VM_Version::determine_features() { - platform_features(); // platform_features() is os_arch specific. - - assert(has_v9(), "must be"); - - if (UseNiagaraInstrs) { // Limit code generation to Niagara. - _features &= niagara1_msk; - } -} - -static uint64_t saved_features = 0; - -void VM_Version::allow_all() { - saved_features = _features; - _features = full_feature_msk; -} - -void VM_Version::revert() { - _features = saved_features; -} diff --git a/src/hotspot/cpu/sparc/vm_version_sparc.hpp b/src/hotspot/cpu/sparc/vm_version_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vm_version_sparc.hpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef CPU_SPARC_VM_VERSION_SPARC_HPP -#define CPU_SPARC_VM_VERSION_SPARC_HPP - -#include "runtime/abstract_vm_version.hpp" -#include "runtime/globals_extension.hpp" - -class VM_Version: public Abstract_VM_Version { - friend class VMStructs; - friend class JVMCIVMStructs; - -protected: - enum { - ISA_V9, - ISA_POPC, - ISA_VIS1, - ISA_VIS2, - ISA_BLK_INIT, - ISA_FMAF, - ISA_VIS3, - ISA_HPC, - ISA_IMA, - ISA_AES, - ISA_DES, - ISA_KASUMI, - ISA_CAMELLIA, - ISA_MD5, - ISA_SHA1, - ISA_SHA256, - ISA_SHA512, - ISA_MPMUL, - ISA_MONT, - ISA_PAUSE, - ISA_CBCOND, - ISA_CRC32C, - - ISA_FJATHPLUS, - ISA_VIS3B, - ISA_ADI, - ISA_SPARC5, - ISA_MWAIT, - ISA_XMPMUL, - ISA_XMONT, - ISA_PAUSE_NSEC, - ISA_VAMASK, - - ISA_SPARC6, - ISA_DICTUNP, - ISA_FPCMPSHL, - ISA_RLE, - ISA_SHA3, - ISA_FJATHPLUS2, - ISA_VIS3C, - ISA_SPARC5B, - ISA_MME, - - // Synthesised properties: - - CPU_FAST_IDIV, - CPU_FAST_RDPC, - CPU_FAST_BIS, - CPU_FAST_LD, - CPU_FAST_CMOVE, - CPU_FAST_IND_BR, - CPU_BLK_ZEROING - }; - -private: - enum { ISA_last_feature = ISA_MME, - CPU_last_feature = CPU_BLK_ZEROING }; - - enum { - ISA_unknown_msk = 0, - - ISA_v9_msk = UINT64_C(1) << ISA_V9, - - ISA_popc_msk = UINT64_C(1) << ISA_POPC, - ISA_vis1_msk = UINT64_C(1) << ISA_VIS1, - ISA_vis2_msk = UINT64_C(1) << ISA_VIS2, - ISA_blk_init_msk = UINT64_C(1) << ISA_BLK_INIT, - ISA_fmaf_msk = UINT64_C(1) << ISA_FMAF, - ISA_vis3_msk = UINT64_C(1) << ISA_VIS3, - ISA_hpc_msk = UINT64_C(1) << ISA_HPC, - ISA_ima_msk = UINT64_C(1) << ISA_IMA, - ISA_aes_msk = UINT64_C(1) << ISA_AES, - ISA_des_msk = UINT64_C(1) << ISA_DES, - ISA_kasumi_msk = UINT64_C(1) << ISA_KASUMI, - ISA_camellia_msk = UINT64_C(1) << ISA_CAMELLIA, - ISA_md5_msk = UINT64_C(1) << ISA_MD5, - ISA_sha1_msk = UINT64_C(1) << ISA_SHA1, - ISA_sha256_msk = UINT64_C(1) << ISA_SHA256, - ISA_sha512_msk = UINT64_C(1) << ISA_SHA512, - ISA_mpmul_msk = UINT64_C(1) << ISA_MPMUL, - ISA_mont_msk = UINT64_C(1) << ISA_MONT, - ISA_pause_msk = UINT64_C(1) << ISA_PAUSE, - ISA_cbcond_msk = UINT64_C(1) << ISA_CBCOND, - ISA_crc32c_msk = UINT64_C(1) << ISA_CRC32C, - - ISA_fjathplus_msk = UINT64_C(1) << ISA_FJATHPLUS, - ISA_vis3b_msk = UINT64_C(1) << ISA_VIS3B, - ISA_adi_msk = UINT64_C(1) << ISA_ADI, - ISA_sparc5_msk = UINT64_C(1) << ISA_SPARC5, - ISA_mwait_msk = UINT64_C(1) << ISA_MWAIT, - ISA_xmpmul_msk = UINT64_C(1) << ISA_XMPMUL, - ISA_xmont_msk = UINT64_C(1) << ISA_XMONT, - ISA_pause_nsec_msk = UINT64_C(1) << ISA_PAUSE_NSEC, - ISA_vamask_msk = UINT64_C(1) << ISA_VAMASK, - - ISA_sparc6_msk = UINT64_C(1) << ISA_SPARC6, - ISA_dictunp_msk = UINT64_C(1) << ISA_DICTUNP, - ISA_fpcmpshl_msk = UINT64_C(1) << ISA_FPCMPSHL, - ISA_rle_msk = UINT64_C(1) << ISA_RLE, - ISA_sha3_msk = UINT64_C(1) << ISA_SHA3, - ISA_fjathplus2_msk = UINT64_C(1) << ISA_FJATHPLUS2, - ISA_vis3c_msk = UINT64_C(1) << ISA_VIS3C, - ISA_sparc5b_msk = UINT64_C(1) << ISA_SPARC5B, - ISA_mme_msk = UINT64_C(1) << ISA_MME, - - CPU_fast_idiv_msk = UINT64_C(1) << CPU_FAST_IDIV, - CPU_fast_rdpc_msk = UINT64_C(1) << CPU_FAST_RDPC, - CPU_fast_bis_msk = UINT64_C(1) << CPU_FAST_BIS, - CPU_fast_ld_msk = UINT64_C(1) << CPU_FAST_LD, - CPU_fast_cmove_msk = UINT64_C(1) << CPU_FAST_CMOVE, - CPU_fast_ind_br_msk = UINT64_C(1) << CPU_FAST_IND_BR, - CPU_blk_zeroing_msk = UINT64_C(1) << CPU_BLK_ZEROING, - - last_feature_msk = CPU_blk_zeroing_msk, - full_feature_msk = (last_feature_msk << 1) - 1 - }; - -/* The following, previously supported, SPARC implementations are no longer - * supported. - * - * UltraSPARC I/II: - * SPARC-V9, VIS - * UltraSPARC III/+: (Cheetah/+) - * SPARC-V9, VIS - * UltraSPARC IV: (Jaguar) - * SPARC-V9, VIS - * UltraSPARC IV+: (Panther) - * SPARC-V9, VIS, POPC - * - * The currently supported SPARC implementations are listed below (including - * generic V9 support). - * - * UltraSPARC T1: (Niagara) - * SPARC-V9, VIS, ASI_BIS (Crypto/hash in SPU) - * UltraSPARC T2: (Niagara-2) - * SPARC-V9, VIS, ASI_BIS, POPC (Crypto/hash in SPU) - * UltraSPARC T2+: (Victoria Falls, etc.) - * SPARC-V9, VIS, VIS2, ASI_BIS, POPC (Crypto/hash in SPU) - * - * UltraSPARC T3: (Rainbow Falls/C2) - * SPARC-V9, VIS, VIS2, ASI_BIS, POPC (Crypto/hash in SPU) - * - * Oracle SPARC T4/T5/M5: (Core C3) - * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND, - * AES, DES, Kasumi, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL - * - * Oracle SPARC M7: (Core C4) - * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND, - * AES, DES, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL, VIS3b, - * ADI, SPARC5, MWAIT, XMPMUL, XMONT, PAUSE_NSEC, VAMASK - * - * Oracle SPARC M8: (Core C5) - * SPARC-V9, VIS, VIS2, VIS3, ASI_BIS, HPC, POPC, FMAF, IMA, PAUSE, CBCOND, - * AES, DES, Camellia, MD5, SHA1, SHA256, SHA512, CRC32C, MONT, MPMUL, VIS3b, - * ADI, SPARC5, MWAIT, XMPMUL, XMONT, PAUSE_NSEC, VAMASK, SPARC6, FPCMPSHL, - * DICTUNP, RLE, SHA3, MME - * - * NOTE: Oracle Number support ignored. - */ - enum { - niagara1_msk = ISA_v9_msk | ISA_vis1_msk | ISA_blk_init_msk, - niagara2_msk = niagara1_msk | ISA_popc_msk, - - core_C2_msk = niagara2_msk | ISA_vis2_msk, - - core_C3_msk = core_C2_msk | ISA_fmaf_msk | ISA_vis3_msk | ISA_hpc_msk | - ISA_ima_msk | ISA_aes_msk | ISA_des_msk | ISA_kasumi_msk | - ISA_camellia_msk | ISA_md5_msk | ISA_sha1_msk | ISA_sha256_msk | - ISA_sha512_msk | ISA_mpmul_msk | ISA_mont_msk | ISA_pause_msk | - ISA_cbcond_msk | ISA_crc32c_msk, - - core_C4_msk = core_C3_msk - ISA_kasumi_msk | - ISA_vis3b_msk | ISA_adi_msk | ISA_sparc5_msk | ISA_mwait_msk | - ISA_xmpmul_msk | ISA_xmont_msk | ISA_pause_nsec_msk | ISA_vamask_msk, - - core_C5_msk = core_C4_msk | ISA_sparc6_msk | ISA_dictunp_msk | - ISA_fpcmpshl_msk | ISA_rle_msk | ISA_sha3_msk | ISA_mme_msk, - - ultra_sparc_t1_msk = niagara1_msk, - ultra_sparc_t2_msk = niagara2_msk, - ultra_sparc_t3_msk = core_C2_msk, - ultra_sparc_m5_msk = core_C3_msk, // NOTE: First out-of-order pipeline. - ultra_sparc_m7_msk = core_C4_msk, - ultra_sparc_m8_msk = core_C5_msk - }; - - static uint _L2_data_cache_line_size; - static uint L2_data_cache_line_size() { return _L2_data_cache_line_size; } - - static void determine_features(); - static void platform_features(); - static void print_features(); - -public: - enum { - // Adopt a conservative behaviour (modelling single-insn-fetch-n-issue) for - // Niagara (and SPARC64). While there are at least two entries/slots in the - // instruction fetch buffer on any Niagara core (and as many as eight on a - // SPARC64), the performance improvement from keeping hot branch targets on - // optimally aligned addresses is such a small one (if any) that we choose - // not to use the extra code space required. - - insn_fetch_alignment = 4 // Byte alignment in L1 insn. cache. - }; - - static void initialize(); - - static void init_before_ergo() { determine_features(); } - - // Instruction feature support: - - static bool has_v9() { return (_features & ISA_v9_msk) != 0; } - static bool has_popc() { return (_features & ISA_popc_msk) != 0; } - static bool has_vis1() { return (_features & ISA_vis1_msk) != 0; } - static bool has_vis2() { return (_features & ISA_vis2_msk) != 0; } - static bool has_blk_init() { return (_features & ISA_blk_init_msk) != 0; } - static bool has_fmaf() { return (_features & ISA_fmaf_msk) != 0; } - static bool has_vis3() { return (_features & ISA_vis3_msk) != 0; } - static bool has_hpc() { return (_features & ISA_hpc_msk) != 0; } - static bool has_ima() { return (_features & ISA_ima_msk) != 0; } - static bool has_aes() { return (_features & ISA_aes_msk) != 0; } - static bool has_des() { return (_features & ISA_des_msk) != 0; } - static bool has_kasumi() { return (_features & ISA_kasumi_msk) != 0; } - static bool has_camellia() { return (_features & ISA_camellia_msk) != 0; } - static bool has_md5() { return (_features & ISA_md5_msk) != 0; } - static bool has_sha1() { return (_features & ISA_sha1_msk) != 0; } - static bool has_sha256() { return (_features & ISA_sha256_msk) != 0; } - static bool has_sha512() { return (_features & ISA_sha512_msk) != 0; } - static bool has_mpmul() { return (_features & ISA_mpmul_msk) != 0; } - static bool has_mont() { return (_features & ISA_mont_msk) != 0; } - static bool has_pause() { return (_features & ISA_pause_msk) != 0; } - static bool has_cbcond() { return (_features & ISA_cbcond_msk) != 0; } - static bool has_crc32c() { return (_features & ISA_crc32c_msk) != 0; } - - static bool has_athena_plus() { return (_features & ISA_fjathplus_msk) != 0; } - static bool has_vis3b() { return (_features & ISA_vis3b_msk) != 0; } - static bool has_adi() { return (_features & ISA_adi_msk) != 0; } - static bool has_sparc5() { return (_features & ISA_sparc5_msk) != 0; } - static bool has_mwait() { return (_features & ISA_mwait_msk) != 0; } - static bool has_xmpmul() { return (_features & ISA_xmpmul_msk) != 0; } - static bool has_xmont() { return (_features & ISA_xmont_msk) != 0; } - static bool has_pause_nsec() { return (_features & ISA_pause_nsec_msk) != 0; } - static bool has_vamask() { return (_features & ISA_vamask_msk) != 0; } - - static bool has_sparc6() { return (_features & ISA_sparc6_msk) != 0; } - static bool has_dictunp() { return (_features & ISA_dictunp_msk) != 0; } - static bool has_fpcmpshl() { return (_features & ISA_fpcmpshl_msk) != 0; } - static bool has_rle() { return (_features & ISA_rle_msk) != 0; } - static bool has_sha3() { return (_features & ISA_sha3_msk) != 0; } - static bool has_athena_plus2() { return (_features & ISA_fjathplus2_msk) != 0; } - static bool has_vis3c() { return (_features & ISA_vis3c_msk) != 0; } - static bool has_sparc5b() { return (_features & ISA_sparc5b_msk) != 0; } - static bool has_mme() { return (_features & ISA_mme_msk) != 0; } - - static bool has_fast_idiv() { return (_features & CPU_fast_idiv_msk) != 0; } - static bool has_fast_rdpc() { return (_features & CPU_fast_rdpc_msk) != 0; } - static bool has_fast_bis() { return (_features & CPU_fast_bis_msk) != 0; } - static bool has_fast_ld() { return (_features & CPU_fast_ld_msk) != 0; } - static bool has_fast_cmove() { return (_features & CPU_fast_cmove_msk) != 0; } - - // If indirect and direct branching is equally fast. - static bool has_fast_ind_br() { return (_features & CPU_fast_ind_br_msk) != 0; } - // If SPARC BIS to the beginning of cache line always zeros it. - static bool has_blk_zeroing() { return (_features & CPU_blk_zeroing_msk) != 0; } - - static bool supports_compare_and_exchange() { return true; } - - // FIXME: To be removed. - static bool is_post_niagara() { - return (_features & niagara2_msk) == niagara2_msk; - } - - // Default prefetch block size on SPARC. - static uint prefetch_data_size() { return L2_data_cache_line_size(); } - - private: - // Prefetch policy and characteristics: - // - // These support routines are used in order to isolate any CPU/core specific - // logic from the actual flag/option processing. They should reflect the HW - // characteristics for the associated options on the current platform. - // - // The three Prefetch* options below (assigned -1 in the configuration) are - // treated according to (given the accepted range [-1..]): - // -1: Determine a proper HW-specific value for the current HW. - // 0: Off - // >0: Command-line supplied value to use. - // - // FIXME: The documentation string in the configuration is wrong, saying that - // -1 is also interpreted as off. - // - static intx prefetch_copy_interval_in_bytes() { - intx bytes = PrefetchCopyIntervalInBytes; - return bytes < 0 ? 512 : bytes; - } - static intx prefetch_scan_interval_in_bytes() { - intx bytes = PrefetchScanIntervalInBytes; - return bytes < 0 ? 512 : bytes; - } - static intx prefetch_fields_ahead() { - intx count = PrefetchFieldsAhead; - return count < 0 ? 0 : count; - } - - // AllocatePrefetchDistance is treated under the same interpretation as the - // Prefetch* options above (i.e., -1, 0, >0). - static intx allocate_prefetch_distance() { - intx count = AllocatePrefetchDistance; - return count < 0 ? 512 : count; - } - - // AllocatePrefetchStyle is guaranteed to be in range [0..3] defined by the - // configuration. - static intx allocate_prefetch_style() { - intx distance = allocate_prefetch_distance(); - // Return 0 (off/none) if AllocatePrefetchDistance was not defined. - return distance > 0 ? AllocatePrefetchStyle : 0; - } - - public: - // Assembler testing - static void allow_all(); - static void revert(); - - // Override the Abstract_VM_Version implementation. - // - // FIXME: Removed broken test on sun4v (always false when invoked prior to the - // proper capability setup), thus always returning 2. Still need to fix - // this properly in order to enable complete page size support. - static uint page_size_count() { return 2; } - - // Override default denominator for ParallelGCThreads. - // - // FIXME: Simply checking the processor family is insufficient. - static uint parallel_worker_threads_denominator() { - return is_post_niagara() ? 16 : 8; - } -}; - -#endif // CPU_SPARC_VM_VERSION_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/vmreg_sparc.cpp b/src/hotspot/cpu/sparc/vmreg_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vmreg_sparc.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2006, 2010, 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. - * - */ - -#include "precompiled.hpp" -#include "code/vmreg.hpp" - - - -void VMRegImpl::set_regName() { - Register reg = ::as_Register(0); - int i; - for (i = 0; i < ConcreteRegisterImpl::max_gpr ; ) { - regName[i++ ] = reg->name(); - regName[i++ ] = reg->name(); - reg = reg->successor(); - } - - FloatRegister freg = ::as_FloatRegister(0); - for ( ; i < ConcreteRegisterImpl::max_fpr ; ) { - regName[i++] = freg->name(); - if (freg->encoding() > 31) { - regName[i++] = freg->name(); - } - freg = freg->successor(); - } - - for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) { - regName[i] = "NON-GPR-FPR"; - } -} diff --git a/src/hotspot/cpu/sparc/vmreg_sparc.hpp b/src/hotspot/cpu/sparc/vmreg_sparc.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vmreg_sparc.hpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2006, 2019, 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. - * - */ - -#ifndef CPU_SPARC_VMREG_SPARC_HPP -#define CPU_SPARC_VMREG_SPARC_HPP - -inline bool is_Register() { return value() >= 0 && value() < ConcreteRegisterImpl::max_gpr; } -inline bool is_FloatRegister() { return value() >= ConcreteRegisterImpl::max_gpr && - value() < ConcreteRegisterImpl::max_fpr; } -inline Register as_Register() { - assert( is_Register() && is_even(value()), "even-aligned GPR name" ); - // Yuk - return ::as_Register(value()>>1); -} - -inline FloatRegister as_FloatRegister() { - assert( is_FloatRegister(), "must be" ); - // Yuk - return ::as_FloatRegister( value() - ConcreteRegisterImpl::max_gpr ); -} - -inline bool is_concrete() { - assert(is_reg(), "must be"); - int v = value(); - if ( v < ConcreteRegisterImpl::max_gpr ) { - return is_even(v); - } - // F0..F31 - if ( v <= ConcreteRegisterImpl::max_gpr + 31) return true; - if ( v < ConcreteRegisterImpl::max_fpr) { - return is_even(v); - } - assert(false, "what register?"); - return false; -} - -#endif // CPU_SPARC_VMREG_SPARC_HPP diff --git a/src/hotspot/cpu/sparc/vmreg_sparc.inline.hpp b/src/hotspot/cpu/sparc/vmreg_sparc.inline.hpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vmreg_sparc.inline.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2006, 2019, 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. - * - */ - -#ifndef CPU_SPARC_VMREG_SPARC_INLINE_HPP -#define CPU_SPARC_VMREG_SPARC_INLINE_HPP - -inline VMReg RegisterImpl::as_VMReg() { - if( this==noreg ) return VMRegImpl::Bad(); - return VMRegImpl::as_VMReg(encoding() << 1 ); -} - -inline VMReg FloatRegisterImpl::as_VMReg() { return VMRegImpl::as_VMReg( ConcreteRegisterImpl::max_gpr + encoding() ); } - - - -#endif // CPU_SPARC_VMREG_SPARC_INLINE_HPP diff --git a/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp b/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp deleted file mode 100644 --- a/src/hotspot/cpu/sparc/vtableStubs_sparc.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (c) 1997, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/vtableStubs.hpp" -#include "interp_masm_sparc.hpp" -#include "memory/resourceArea.hpp" -#include "oops/compiledICHolder.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/klassVtable.hpp" -#include "runtime/sharedRuntime.hpp" -#include "vmreg_sparc.inline.hpp" -#ifdef COMPILER2 -#include "opto/runtime.hpp" -#endif - -// machine-dependent part of VtableStubs: create vtableStub of correct size and -// initialize its code - -#define __ masm-> - -#ifndef PRODUCT -extern "C" void bad_compiled_vtable_index(JavaThread* thread, oopDesc* receiver, int index); -#endif - - -// Used by compiler only; may use only caller saved, non-argument registers -VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { - // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. - const int stub_code_length = code_size_limit(true); - VtableStub* s = new(stub_code_length) VtableStub(true, vtable_index); - // Can be NULL if there is no free space in the code cache. - if (s == NULL) { - return NULL; - } - - // Count unused bytes in instruction sequences of variable size. - // We add them to the computed buffer size in order to avoid - // overflow in subsequently generated stubs. - address start_pc; - int slop_bytes = 0; - int slop_delta = 0; - const int index_dependent_slop = ((vtable_index < 512) ? 2 : 0)*BytesPerInstWord; // code size change with transition from 13-bit to 32-bit constant (@index == 512?). - - ResourceMark rm; - CodeBuffer cb(s->entry_point(), stub_code_length); - MacroAssembler* masm = new MacroAssembler(&cb); - -#if (!defined(PRODUCT) && defined(COMPILER2)) - if (CountCompiledCalls) { - __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), G5, G3_scratch); - } -#endif // PRODUCT - - assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); - - // get receiver klass - address npe_addr = __ pc(); - __ load_klass(O0, G3_scratch); - -#ifndef PRODUCT - if (DebugVtables) { - Label L; - // check offset vs vtable length - __ ld(G3_scratch, in_bytes(Klass::vtable_length_offset()), G5); - __ cmp_and_br_short(G5, vtable_index*vtableEntry::size(), Assembler::greaterUnsigned, Assembler::pt, L); - - // set generates 8 instructions (worst case), 1 instruction (best case) - start_pc = __ pc(); - __ set(vtable_index, O2); - slop_delta = __ worst_case_insts_for_set()*BytesPerInstWord - (__ pc() - start_pc); - slop_bytes += slop_delta; - assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta); - - // there is no variance in call_VM() emitted code. - __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), O0, O2); - __ bind(L); - } -#endif - - // set Method* (in case of interpreted method), and destination address - start_pc = __ pc(); - __ lookup_virtual_method(G3_scratch, vtable_index, G5_method); - // lookup_virtual_method generates 3 instructions (worst case), 1 instruction (best case) - slop_delta = 3*BytesPerInstWord - (int)(__ pc() - start_pc); - slop_bytes += slop_delta; - assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta); - -#ifndef PRODUCT - if (DebugVtables) { - Label L; - __ br_notnull_short(G5_method, Assembler::pt, L); - __ stop("Vtable entry is ZERO"); - __ bind(L); - } -#endif - - address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract - // NOTE: for vtable dispatches, the vtable entry will never be null. - - __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); - - // jump to target (either compiled code or c2iadapter) - __ JMP(G3_scratch, 0); - // load Method* (in case we call c2iadapter) - __ delayed()->nop(); - - masm->flush(); - slop_bytes += index_dependent_slop; // add'l slop for size variance due to large itable offsets - bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, index_dependent_slop); - - return s; -} - - -VtableStub* VtableStubs::create_itable_stub(int itable_index) { - // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. - const int stub_code_length = code_size_limit(false); - VtableStub* s = new(stub_code_length) VtableStub(false, itable_index); - // Can be NULL if there is no free space in the code cache. - if (s == NULL) { - return NULL; - } - // Count unused bytes in instruction sequences of variable size. - // We add them to the computed buffer size in order to avoid - // overflow in subsequently generated stubs. - address start_pc; - int slop_bytes = 0; - int slop_delta = 0; - const int index_dependent_slop = ((itable_index < 512) ? 2 : 0)*BytesPerInstWord; // code size change with transition from 13-bit to 32-bit constant (@index == 512?). - - ResourceMark rm; - CodeBuffer cb(s->entry_point(), stub_code_length); - MacroAssembler* masm = new MacroAssembler(&cb); - -#if (!defined(PRODUCT) && defined(COMPILER2)) - if (CountCompiledCalls) { -// Use G3_scratch, G4_scratch as work regs for inc_counter. -// These are defined before use further down. - __ inc_counter(SharedRuntime::nof_megamorphic_calls_addr(), G3_scratch, G4_scratch); - } -#endif // PRODUCT - - Register G3_Klass = G3_scratch; - Register G5_icholder = G5; // Passed in as an argument - Register G4_interface = G4_scratch; - - // Entry arguments: - // G5_interface: Interface - // O0: Receiver - assert(VtableStub::receiver_location() == O0->as_VMReg(), "receiver expected in O0"); - - // get receiver klass (also an implicit null-check) - address npe_addr = __ pc(); - __ load_klass(O0, G3_Klass); - - // Push a new window to get some temp registers. This chops the head of all - // my 64-bit %o registers in the LION build, but this is OK because no longs - // are passed in the %o registers. Instead, longs are passed in G1 and G4 - // and so those registers are not available here. - __ save(SP,-frame::register_save_words*wordSize,SP); - - Label L_no_such_interface; - Register L5_method = L5; - - start_pc = __ pc(); - - // Receiver subtype check against REFC. - __ ld_ptr(G5_icholder, CompiledICHolder::holder_klass_offset(), G4_interface); - __ lookup_interface_method(// inputs: rec. class, interface, itable index - G3_Klass, G4_interface, itable_index, - // outputs: scan temp. reg1, scan temp. reg2 - L5_method, L2, L3, - L_no_such_interface, - /*return_method=*/ false); - - const ptrdiff_t typecheckSize = __ pc() - start_pc; - start_pc = __ pc(); - - // Get Method* and entrypoint for compiler - __ ld_ptr(G5_icholder, CompiledICHolder::holder_metadata_offset(), G4_interface); - __ lookup_interface_method(// inputs: rec. class, interface, itable index - G3_Klass, G4_interface, itable_index, - // outputs: method, scan temp. reg - L5_method, L2, L3, - L_no_such_interface); - - const ptrdiff_t lookupSize = __ pc() - start_pc; - - // Reduce "estimate" such that "padding" does not drop below 8. - // Do not target a left-over number of zero, because a very - // large vtable or itable offset (> 4K) will require an extra - // sethi/or pair of instructions. - // Found typecheck(60) + lookup(72) to exceed previous extimate (32*4). - const ptrdiff_t estimate = 36*BytesPerInstWord; - const ptrdiff_t codesize = typecheckSize + lookupSize + index_dependent_slop; - slop_delta = (int)(estimate - codesize); - slop_bytes += slop_delta; - assert(slop_delta >= 0, "itable #%d: Code size estimate (%d) for lookup_interface_method too small, required: %d", itable_index, (int)estimate, (int)codesize); - -#ifndef PRODUCT - if (DebugVtables) { - Label L01; - __ br_notnull_short(L5_method, Assembler::pt, L01); - __ stop("Method* is null"); - __ bind(L01); - } -#endif - - // If the following load is through a NULL pointer, we'll take an OS - // exception that should translate into an AbstractMethodError. We need the - // window count to be correct at that time. - __ restore(L5_method, 0, G5_method); - // Restore registers *before* the AME point. - - address ame_addr = __ pc(); // if the vtable entry is null, the method is abstract - __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3_scratch); - - // G5_method: Method* - // O0: Receiver - // G3_scratch: entry point - __ JMP(G3_scratch, 0); - __ delayed()->nop(); - - __ bind(L_no_such_interface); - // Handle IncompatibleClassChangeError in itable stubs. - // More detailed error message. - // We force resolving of the call site by jumping to the "handle - // wrong method" stub, and so let the interpreter runtime do all the - // dirty work. - AddressLiteral icce(SharedRuntime::get_handle_wrong_method_stub()); - __ jump_to(icce, G3_scratch); - __ delayed()->restore(); - - masm->flush(); - slop_bytes += index_dependent_slop; // add'l slop for size variance due to large itable offsets - bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, index_dependent_slop); - - return s; -} - -int VtableStub::pd_code_alignment() { - // UltraSPARC cache line size is 8 instructions: - const unsigned int icache_line_size = 32; - return icache_line_size; -} diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp @@ -65,7 +65,7 @@ #define INCLUDE_RTM_OPT 1 #endif -#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__) +#if defined(LINUX) || defined(__APPLE__) #define SUPPORT_RESERVED_STACK_AREA #endif diff --git a/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp b/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp --- a/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp +++ b/src/hotspot/cpu/zero/bytecodeInterpreter_zero.hpp @@ -28,7 +28,7 @@ // Platform specific for C++ based Interpreter -#if defined(PPC) || defined(SPARC) || defined(IA64) +#if defined(PPC) || defined(IA64) #define LOTS_OF_REGS // Use plenty of registers #else #undef LOTS_OF_REGS // Loser platforms diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -222,12 +222,6 @@ static char cpu_arch[] = "arm"; #elif defined(PPC32) static char cpu_arch[] = "ppc"; -#elif defined(SPARC) - #ifdef _LP64 -static char cpu_arch[] = "sparcv9"; - #else -static char cpu_arch[] = "sparc"; - #endif #else #error Add appropriate cpu_arch setting #endif @@ -1365,9 +1359,6 @@ {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"}, {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"}, - {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, - {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, - {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, @@ -1385,10 +1376,6 @@ static Elf32_Half running_arch_code=EM_X86_64; #elif (defined IA64) static Elf32_Half running_arch_code=EM_IA_64; - #elif (defined __sparc) && (defined _LP64) - static Elf32_Half running_arch_code=EM_SPARCV9; - #elif (defined __sparc) && (!defined _LP64) - static Elf32_Half running_arch_code=EM_SPARC; #elif (defined __powerpc64__) static Elf32_Half running_arch_code=EM_PPC64; #elif (defined __powerpc__) @@ -1409,7 +1396,7 @@ static Elf32_Half running_arch_code=EM_68K; #else #error Method os::dll_load requires that one of following is defined:\ - IA32, AMD64, IA64, __sparc, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K + IA32, AMD64, IA64, __powerpc__, ARM, S390, ALPHA, MIPS, MIPSEL, PARISC, M68K #endif // Identify compatability class for VM's architecture and library's architecture diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -318,7 +318,7 @@ #ifndef SYS_gettid -// i386: 224, ia64: 1105, amd64: 186, sparc 143 +// i386: 224, ia64: 1105, amd64: 186 #ifdef __ia64__ #define SYS_gettid 1105 #else @@ -328,11 +328,7 @@ #ifdef __amd64__ #define SYS_gettid 186 #else - #ifdef __sparc__ - #define SYS_gettid 143 - #else - #error define gettid for the arch - #endif + #error define gettid for the arch #endif #endif #endif @@ -408,7 +404,7 @@ // ... // 7: The default directories, normally /lib and /usr/lib. #ifndef OVERRIDE_LIBPATH - #if defined(AMD64) || (defined(_LP64) && defined(SPARC)) || defined(PPC64) || defined(S390) + #if defined(AMD64) || defined(PPC64) || defined(S390) #define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib" #else #define DEFAULT_LIBPATH "/lib:/usr/lib" @@ -1850,9 +1846,6 @@ {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"}, {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"}, - {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, - {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, - {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, #if defined(VM_LITTLE_ENDIAN) {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64 LE"}, @@ -1879,10 +1872,6 @@ static Elf32_Half running_arch_code=EM_X86_64; #elif (defined IA64) static Elf32_Half running_arch_code=EM_IA_64; -#elif (defined __sparc) && (defined _LP64) - static Elf32_Half running_arch_code=EM_SPARCV9; -#elif (defined __sparc) && (!defined _LP64) - static Elf32_Half running_arch_code=EM_SPARC; #elif (defined __powerpc64__) static Elf32_Half running_arch_code=EM_PPC64; #elif (defined __powerpc__) @@ -1909,7 +1898,7 @@ static Elf32_Half running_arch_code=EM_RISCV; #else #error Method os::dll_load requires that one of following is defined:\ - AARCH64, ALPHA, ARM, AMD64, IA32, IA64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH, __sparc + AARCH64, ALPHA, ARM, AMD64, IA32, IA64, M68K, MIPS, MIPSEL, PARISC, __powerpc__, __powerpc64__, RISCV, S390, SH #endif // Identify compatibility class for VM's architecture and library's architecture @@ -2549,8 +2538,6 @@ const char* search_string = "cpu"; #elif defined(S390) const char* search_string = "machine ="; -#elif defined(SPARC) -const char* search_string = "cpu"; #else const char* search_string = "Processor"; #endif @@ -2602,8 +2589,6 @@ strncpy(cpuinfo, "PPC64", length); #elif defined(S390) strncpy(cpuinfo, "S390", length); -#elif defined(SPARC) - strncpy(cpuinfo, "sparcv9", length); #elif defined(ZERO_LIBARCH) strncpy(cpuinfo, ZERO_LIBARCH, length); #else @@ -3782,8 +3767,7 @@ IA32_ONLY(4 * M) IA64_ONLY(256 * M) PPC_ONLY(4 * M) - S390_ONLY(1 * M) - SPARC_ONLY(4 * M); + S390_ONLY(1 * M); #endif // ZERO FILE *fp = fopen("/proc/meminfo", "r"); diff --git a/src/hotspot/os/posix/include/jvm_md.h b/src/hotspot/os/posix/include/jvm_md.h --- a/src/hotspot/os/posix/include/jvm_md.h +++ b/src/hotspot/os/posix/include/jvm_md.h @@ -54,7 +54,7 @@ #endif #define JNI_LIB_NAME(NAME) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX -#if defined(AIX) || defined(SOLARIS) +#if defined(AIX) #define JVM_MAXPATHLEN MAXPATHLEN #else // Hack: MAXPATHLEN is 4095 on some Linux and 4096 on others. This may @@ -87,14 +87,8 @@ #define JVM_SIGTERM SIGTERM #define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */ -#ifdef SOLARIS -#define ASYNC_SIGNAL SIGJVM2 /* Event-based suspend/resume support */ -#endif // SOLARIS #define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */ #define SHUTDOWN2_SIGNAL SIGINT #define SHUTDOWN3_SIGNAL SIGTERM -/* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */ -#define JSIG_VERSION_1_4_1 0x30140100 - #endif /* !_JAVASOFT_JVM_MD_H_ */ diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -448,7 +448,7 @@ st->print("%d", sysconf(_SC_CHILD_MAX)); print_rlimit(st, ", THREADS", RLIMIT_THREADS); -#elif !defined(SOLARIS) +#else print_rlimit(st, ", NPROC", RLIMIT_NPROC); #endif @@ -466,12 +466,6 @@ print_rlimit(st, ", MEMLOCK", RLIMIT_MEMLOCK, true); #endif -#if defined(SOLARIS) - // maximum size of mapped address space of a process in bytes; - // if the limit is exceeded, mmap and brk fail - print_rlimit(st, ", VMEM", RLIMIT_VMEM, true); -#endif - // MacOS; The maximum size (in bytes) to which a process's resident set size may grow. #if defined(__APPLE__) print_rlimit(st, ", RSS", RLIMIT_RSS, true); @@ -1095,21 +1089,6 @@ #if defined(IA64) && !defined(AIX) { SIGSEGV, SEGV_PSTKOVF, "SEGV_PSTKOVF", "Paragraph stack overflow" }, #endif -#if defined(__sparc) && defined(SOLARIS) -// define Solaris Sparc M7 ADI SEGV signals -#if !defined(SEGV_ACCADI) -#define SEGV_ACCADI 3 -#endif - { SIGSEGV, SEGV_ACCADI, "SEGV_ACCADI", "ADI not enabled for mapped object." }, -#if !defined(SEGV_ACCDERR) -#define SEGV_ACCDERR 4 -#endif - { SIGSEGV, SEGV_ACCDERR, "SEGV_ACCDERR", "ADI disrupting exception." }, -#if !defined(SEGV_ACCPERR) -#define SEGV_ACCPERR 5 -#endif - { SIGSEGV, SEGV_ACCPERR, "SEGV_ACCPERR", "ADI precise exception." }, -#endif // defined(__sparc) && defined(SOLARIS) { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." }, { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." }, { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." }, @@ -1268,13 +1247,7 @@ bool os::signal_thread(Thread* thread, int sig, const char* reason) { OSThread* osthread = thread->osthread(); if (osthread) { -#if defined (SOLARIS) - // Note: we cannot use pthread_kill on Solaris - not because - // its missing, but because we do not have the pthread_t id. - int status = thr_kill(osthread->thread_id(), sig); -#else int status = pthread_kill(osthread->pthread_id(), sig); -#endif if (status == 0) { Events::log(Thread::current(), "sent signal %d to Thread " INTPTR_FORMAT " because %s.", sig, p2i(thread), reason); @@ -1295,8 +1268,6 @@ return Bsd::ucontext_get_pc(ctx); #elif defined(LINUX) return Linux::ucontext_get_pc(ctx); -#elif defined(SOLARIS) - return Solaris::ucontext_get_pc(ctx); #else VMError::report_and_die("unimplemented ucontext_get_pc"); #endif @@ -1309,8 +1280,6 @@ Bsd::ucontext_set_pc(ctx, pc); #elif defined(LINUX) Linux::ucontext_set_pc(ctx, pc); -#elif defined(SOLARIS) - Solaris::ucontext_set_pc(ctx, pc); #else VMError::report_and_die("unimplemented ucontext_get_pc"); #endif @@ -1415,7 +1384,7 @@ // page size which again depends on the concrete system the VM is running // on. Space for libc guard pages is not included in this size. jint os::Posix::set_minimum_stack_sizes() { - size_t os_min_stack_allowed = SOLARIS_ONLY(thr_min_stack()) NOT_SOLARIS(PTHREAD_STACK_MIN); + size_t os_min_stack_allowed = PTHREAD_STACK_MIN; _java_thread_min_stack_allowed = _java_thread_min_stack_allowed + JavaThread::stack_guard_zone_size() + @@ -1625,11 +1594,9 @@ if ((status = pthread_mutexattr_settype(_mutexAttr, PTHREAD_MUTEX_NORMAL)) != 0) { fatal("pthread_mutexattr_settype: %s", os::strerror(status)); } - // Solaris has it's own PlatformMutex, distinct from the one for POSIX. - NOT_SOLARIS(os::PlatformMutex::init();) + os::PlatformMutex::init(); } -#ifndef SOLARIS sigset_t sigs; struct sigaction sigact[NSIG]; @@ -1645,7 +1612,6 @@ sigact[sig] = oldAct; sigaddset(&sigs, sig); } -#endif // Not all POSIX types and API's are available on all notionally "posix" // platforms. If we have build-time support then we will check for actual @@ -1730,7 +1696,6 @@ pthread_init_common(); -#ifndef SOLARIS int status; if (_pthread_condattr_setclock != NULL && _clock_gettime != NULL) { if ((status = _pthread_condattr_setclock(_condAttr, CLOCK_MONOTONIC)) != 0) { @@ -1745,12 +1710,9 @@ _use_clock_monotonic_condattr = true; } } -#endif // !SOLARIS - } void os::Posix::init_2(void) { -#ifndef SOLARIS log_info(os)("Use of CLOCK_MONOTONIC is%s supported", (_clock_gettime != NULL ? "" : " not")); log_info(os)("Use of pthread_condattr_setclock is%s supported", @@ -1758,7 +1720,6 @@ log_info(os)("Relative timed-wait using pthread_cond_timedwait is associated with %s", _use_clock_monotonic_condattr ? "CLOCK_MONOTONIC" : "the default clock"); sigemptyset(&sigs); -#endif // !SOLARIS } #else // !SUPPORTS_CLOCK_MONOTONIC @@ -1768,12 +1729,10 @@ } void os::Posix::init_2(void) { -#ifndef SOLARIS log_info(os)("Use of CLOCK_MONOTONIC is not supported"); log_info(os)("Use of pthread_condattr_setclock is not supported"); log_info(os)("Relative timed-wait using pthread_cond_timedwait is associated with the default clock"); sigemptyset(&sigs); -#endif // !SOLARIS } #endif // SUPPORTS_CLOCK_MONOTONIC @@ -1914,7 +1873,6 @@ // Shared pthread_mutex/cond based PlatformEvent implementation. // Not currently usable by Solaris. -#ifndef SOLARIS // PlatformEvent // @@ -2346,5 +2304,3 @@ return OS_OK; } } - -#endif // !SOLARIS diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -172,7 +172,6 @@ sigjmp_buf _jmpbuf; }; -#ifndef SOLARIS /* * This is the platform-specific implementation underpinning @@ -336,6 +335,4 @@ void notify_all(); }; -#endif // !SOLARIS - #endif // OS_POSIX_OS_POSIX_HPP diff --git a/src/hotspot/os/posix/os_posix.inline.hpp b/src/hotspot/os/posix/os_posix.inline.hpp --- a/src/hotspot/os/posix/os_posix.inline.hpp +++ b/src/hotspot/os/posix/os_posix.inline.hpp @@ -45,8 +45,6 @@ #endif // SUPPORTS_CLOCK_MONOTONIC -#ifndef SOLARIS - // Platform Mutex/Monitor implementation inline void os::PlatformMutex::lock() { @@ -75,6 +73,4 @@ assert_status(status == 0, status, "cond_broadcast"); } -#endif // !SOLARIS - #endif // OS_POSIX_OS_POSIX_INLINE_HPP diff --git a/src/hotspot/os/posix/vmError_posix.cpp b/src/hotspot/os/posix/vmError_posix.cpp --- a/src/hotspot/os/posix/vmError_posix.cpp +++ b/src/hotspot/os/posix/vmError_posix.cpp @@ -38,9 +38,6 @@ #include #include #endif -#ifdef SOLARIS -#include -#endif #ifdef AIX #include #endif diff --git a/src/hotspot/os/solaris/attachListener_solaris.cpp b/src/hotspot/os/solaris/attachListener_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/attachListener_solaris.cpp +++ /dev/null @@ -1,781 +0,0 @@ -/* - * Copyright (c) 2005, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "logging/log.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/os.inline.hpp" -#include "services/attachListener.hpp" -#include "services/dtraceAttacher.hpp" -#include "utilities/vmError.hpp" - -#include -#include -#include -#include -#include -#include -#include - -// stropts.h uses STR in stream ioctl defines -#undef STR -#include -#undef STR -#define STR(a) #a - -// The attach mechanism on Solaris is implemented using the Doors IPC -// mechanism. The first tool to attempt to attach causes the attach -// listener thread to startup. This thread creats a door that is -// associated with a function that enqueues an operation to the attach -// listener. The door is attached to a file in the file system so that -// client (tools) can locate it. To enqueue an operation to the VM the -// client calls through the door which invokes the enqueue function in -// this process. The credentials of the client are checked and if the -// effective uid matches this process then the operation is enqueued. -// When an operation completes the attach listener is required to send the -// operation result and any result data to the client. In this implementation -// the result is returned via a UNIX domain socket. A pair of connected -// sockets (socketpair) is created in the enqueue function and the file -// descriptor for one of the sockets is returned to the client as the -// return from the door call. The other end is retained in this process. -// When the operation completes the result is sent to the client and -// the socket is closed. - -// forward reference -class SolarisAttachOperation; - -class SolarisAttachListener: AllStatic { - private: - - // the path to which we attach the door file descriptor - static char _door_path[PATH_MAX+1]; - static volatile bool _has_door_path; - - // door descriptor returned by door_create - static int _door_descriptor; - - static bool _atexit_registered; - - // mutex to protect operation list - static mutex_t _mutex; - - // semaphore to wakeup listener thread - static sema_t _wakeup; - - static mutex_t* mutex() { return &_mutex; } - static sema_t* wakeup() { return &_wakeup; } - - // enqueued operation list - static SolarisAttachOperation* _head; - static SolarisAttachOperation* _tail; - - static SolarisAttachOperation* head() { return _head; } - static void set_head(SolarisAttachOperation* head) { _head = head; } - - static SolarisAttachOperation* tail() { return _tail; } - static void set_tail(SolarisAttachOperation* tail) { _tail = tail; } - - // create the door - static int create_door(); - - public: - enum { - ATTACH_PROTOCOL_VER = 1 // protocol version - }; - enum { - ATTACH_ERROR_BADREQUEST = 100, // error code returned by - ATTACH_ERROR_BADVERSION = 101, // the door call - ATTACH_ERROR_RESOURCE = 102, - ATTACH_ERROR_INTERNAL = 103, - ATTACH_ERROR_DENIED = 104 - }; - - static void set_door_path(char* path) { - if (path == NULL) { - _door_path[0] = '\0'; - _has_door_path = false; - } else { - strncpy(_door_path, path, PATH_MAX); - _door_path[PATH_MAX] = '\0'; // ensure it's nul terminated - _has_door_path = true; - } - } - - static void set_door_descriptor(int dd) { _door_descriptor = dd; } - - // initialize the listener - static int init(); - - static bool has_door_path() { return _has_door_path; } - static char* door_path() { return _door_path; } - static int door_descriptor() { return _door_descriptor; } - - // enqueue an operation - static void enqueue(SolarisAttachOperation* op); - - // dequeue an operation - static SolarisAttachOperation* dequeue(); -}; - - -// SolarisAttachOperation is an AttachOperation that additionally encapsulates -// a socket connection to the requesting client/tool. SolarisAttachOperation -// can additionally be held in a linked list. - -class SolarisAttachOperation: public AttachOperation { - private: - friend class SolarisAttachListener; - - // connection to client - int _socket; - - // linked list support - SolarisAttachOperation* _next; - - SolarisAttachOperation* next() { return _next; } - void set_next(SolarisAttachOperation* next) { _next = next; } - - public: - void complete(jint res, bufferedStream* st); - - int socket() const { return _socket; } - void set_socket(int s) { _socket = s; } - - SolarisAttachOperation(char* name) : AttachOperation(name) { - set_socket(-1); - set_next(NULL); - } -}; - -// statics -char SolarisAttachListener::_door_path[PATH_MAX+1]; -volatile bool SolarisAttachListener::_has_door_path; -int SolarisAttachListener::_door_descriptor = -1; -bool SolarisAttachListener::_atexit_registered = false; -mutex_t SolarisAttachListener::_mutex; -sema_t SolarisAttachListener::_wakeup; -SolarisAttachOperation* SolarisAttachListener::_head = NULL; -SolarisAttachOperation* SolarisAttachListener::_tail = NULL; - -// Supporting class to help split a buffer into individual components -class ArgumentIterator : public StackObj { - private: - char* _pos; - char* _end; - public: - ArgumentIterator(char* arg_buffer, size_t arg_size) { - _pos = arg_buffer; - _end = _pos + arg_size - 1; - } - char* next() { - if (*_pos == '\0') { - // advance the iterator if possible (null arguments) - if (_pos < _end) { - _pos += 1; - } - return NULL; - } - char* res = _pos; - char* next_pos = strchr(_pos, '\0'); - if (next_pos < _end) { - next_pos++; - } - _pos = next_pos; - return res; - } -}; - -// Calls from the door function to check that the client credentials -// match this process. Returns 0 if credentials okay, otherwise -1. -static int check_credentials() { - ucred_t *cred_info = NULL; - int ret = -1; // deny by default - - // get client credentials - if (door_ucred(&cred_info) == -1) { - return -1; // unable to get them, deny - } - - // get euid/egid from ucred_free - uid_t ucred_euid = ucred_geteuid(cred_info); - gid_t ucred_egid = ucred_getegid(cred_info); - - // check that the effective uid/gid matches - if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) { - ret = 0; // allow - } - - ucred_free(cred_info); - return ret; -} - - -// Parses the argument buffer to create an AttachOperation that we should -// enqueue to the attach listener. -// The buffer is expected to be formatted as follows: -// 00000 -// where is the version number (must be "1"), is the command -// name ("load, "datadump", ...) and is an argument. -// -static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) { - // assume bad request until parsed - *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST; - - if (arg_size < 2 || argp[arg_size-1] != '\0') { - return NULL; // no ver or not null terminated - } - - // Use supporting class to iterate over the buffer - ArgumentIterator args(argp, arg_size); - - // First check the protocol version - char* ver = args.next(); - if (ver == NULL) { - return NULL; - } - if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) { - *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION; - return NULL; - } - - // Get command name and create the operation - char* name = args.next(); - if (name == NULL || strlen(name) > AttachOperation::name_length_max) { - return NULL; - } - SolarisAttachOperation* op = new SolarisAttachOperation(name); - - // Iterate over the arguments - for (int i=0; iset_arg(i, NULL); - } else { - if (strlen(arg) > AttachOperation::arg_length_max) { - delete op; - return NULL; - } - op->set_arg(i, arg); - } - } - - // return operation - *err = 0; - return op; -} - -// create special operation to indicate all clients have detached -static SolarisAttachOperation* create_detachall_operation() { - return new SolarisAttachOperation(AttachOperation::detachall_operation_name()); -} - -// This is door function which the client executes via a door_call. -extern "C" { - static void enqueue_proc(void* cookie, char* argp, size_t arg_size, - door_desc_t* dt, uint_t n_desc) - { - int return_fd = -1; - SolarisAttachOperation* op = NULL; - - // wait up to 10 seconds for listener to be up and running - jint res = 0; - int sleep_count = 0; - while (!AttachListener::is_initialized()) { - sleep(1); // 1 second - sleep_count++; - if (sleep_count > 10) { // try for 10 seconds - debug_only(warning("door_call when not enabled")); - res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL; - break; - } - } - - // check client credentials - if (res == 0) { - if (check_credentials() != 0) { - res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED; - } - } - - // if we are stopped at ShowMessageBoxOnError then maybe we can - // load a diagnostic library - if (res == 0 && VMError::is_error_reported()) { - if (ShowMessageBoxOnError) { - // TBD - support loading of diagnostic library here - } - - // can't enqueue operation after fatal error - res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; - } - - // create the operation - if (res == 0) { - int err; - op = create_operation(argp, arg_size, &err); - res = (op == NULL) ? (jint)err : 0; - } - - // create a pair of connected sockets. Store the file descriptor - // for one end in the operation and enqueue the operation. The - // file descriptor for the other end wil be returned to the client. - if (res == 0) { - int s[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) { - delete op; - res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; - } else { - op->set_socket(s[0]); - return_fd = s[1]; - SolarisAttachListener::enqueue(op); - } - } - - // Return 0 (success) + file descriptor, or non-0 (error) - if (res == 0) { - door_desc_t desc; - // DOOR_RELEASE flag makes sure fd is closed after passing it to - // the client. See door_return(3DOOR) man page. - desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; - desc.d_data.d_desc.d_descriptor = return_fd; - door_return((char*)&res, sizeof(res), &desc, 1); - } else { - door_return((char*)&res, sizeof(res), NULL, 0); - } - } -} - -// atexit hook to detach the door and remove the file -extern "C" { - static void listener_cleanup() { - int dd = SolarisAttachListener::door_descriptor(); - if (dd >= 0) { - SolarisAttachListener::set_door_descriptor(-1); - ::close(dd); - } - if (SolarisAttachListener::has_door_path()) { - char* path = SolarisAttachListener::door_path(); - ::fdetach(path); - ::unlink(path); - SolarisAttachListener::set_door_path(NULL); - } - } -} - -// Create the door -int SolarisAttachListener::create_door() { - char door_path[PATH_MAX+1]; - char initial_path[PATH_MAX+1]; - int fd, res; - - // register exit function - if (!_atexit_registered) { - _atexit_registered = true; - ::atexit(listener_cleanup); - } - - // create the door descriptor - int dd = ::door_create(enqueue_proc, NULL, 0); - if (dd < 0) { - return -1; - } - - // create initial file to attach door descriptor - snprintf(door_path, sizeof(door_path), "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path); - RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd); - if (fd == -1) { - log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno); - ::door_revoke(dd); - return -1; - } - assert(fd >= 0, "bad file descriptor"); - ::close(fd); - - // attach the door descriptor to the file - if ((res = ::fattach(dd, initial_path)) == -1) { - // if busy then detach and try again - if (errno == EBUSY) { - ::fdetach(initial_path); - res = ::fattach(dd, initial_path); - } - if (res == -1) { - log_debug(attach)("unable to create door - fattach failed (%d)", errno); - ::door_revoke(dd); - dd = -1; - } - } - - // rename file so that clients can attach - if (dd >= 0) { - if (::rename(initial_path, door_path) == -1) { - ::close(dd); - ::fdetach(initial_path); - log_debug(attach)("unable to create door - rename %s to %s failed (%d)", errno); - dd = -1; - } - } - if (dd >= 0) { - set_door_descriptor(dd); - set_door_path(door_path); - log_trace(attach)("door file %s created succesfully", door_path); - } else { - // unable to create door, attach it to file, or rename file into place - ::unlink(initial_path); - return -1; - } - - return 0; -} - -// Initialization - create the door, locks, and other initialization -int SolarisAttachListener::init() { - if (create_door()) { - return -1; - } - - int status = os::Solaris::mutex_init(&_mutex); - assert_status(status==0, status, "mutex_init"); - - status = ::sema_init(&_wakeup, 0, NULL, NULL); - assert_status(status==0, status, "sema_init"); - - set_head(NULL); - set_tail(NULL); - - return 0; -} - -// Dequeue an operation -SolarisAttachOperation* SolarisAttachListener::dequeue() { - for (;;) { - int res; - - // wait for somebody to enqueue something - while ((res = ::sema_wait(wakeup())) == EINTR) - ; - if (res) { - warning("sema_wait failed: %s", os::strerror(res)); - return NULL; - } - - // lock the list - res = os::Solaris::mutex_lock(mutex()); - assert(res == 0, "mutex_lock failed"); - - // remove the head of the list - SolarisAttachOperation* op = head(); - if (op != NULL) { - set_head(op->next()); - if (head() == NULL) { - set_tail(NULL); - } - } - - // unlock - os::Solaris::mutex_unlock(mutex()); - - // if we got an operation when return it. - if (op != NULL) { - return op; - } - } -} - -// Enqueue an operation -void SolarisAttachListener::enqueue(SolarisAttachOperation* op) { - // lock list - int res = os::Solaris::mutex_lock(mutex()); - assert(res == 0, "mutex_lock failed"); - - // enqueue at tail - op->set_next(NULL); - if (head() == NULL) { - set_head(op); - } else { - tail()->set_next(op); - } - set_tail(op); - - // wakeup the attach listener - RESTARTABLE(::sema_post(wakeup()), res); - assert(res == 0, "sema_post failed"); - - // unlock - os::Solaris::mutex_unlock(mutex()); -} - - -// support function - writes the (entire) buffer to a socket -static int write_fully(int s, char* buf, int len) { - do { - int n = ::write(s, buf, len); - if (n == -1) { - if (errno != EINTR) return -1; - } else { - buf += n; - len -= n; - } - } - while (len > 0); - return 0; -} - -// Complete an operation by sending the operation result and any result -// output to the client. At this time the socket is in blocking mode so -// potentially we can block if there is a lot of data and the client is -// non-responsive. For most operations this is a non-issue because the -// default send buffer is sufficient to buffer everything. In the future -// if there are operations that involves a very big reply then it the -// socket could be made non-blocking and a timeout could be used. - -void SolarisAttachOperation::complete(jint res, bufferedStream* st) { - if (this->socket() >= 0) { - JavaThread* thread = JavaThread::current(); - ThreadBlockInVM tbivm(thread); - - thread->set_suspend_equivalent(); - // cleared by handle_special_suspend_equivalent_condition() or - // java_suspend_self() via check_and_wait_while_suspended() - - // write operation result - char msg[32]; - sprintf(msg, "%d\n", res); - int rc = write_fully(this->socket(), msg, strlen(msg)); - - // write any result data - if (rc == 0) { - write_fully(this->socket(), (char*) st->base(), st->size()); - ::shutdown(this->socket(), 2); - } - - // close socket and we're done - ::close(this->socket()); - - // were we externally suspended while we were waiting? - thread->check_and_wait_while_suspended(); - } - delete this; -} - - -// AttachListener functions - -AttachOperation* AttachListener::dequeue() { - JavaThread* thread = JavaThread::current(); - ThreadBlockInVM tbivm(thread); - - thread->set_suspend_equivalent(); - // cleared by handle_special_suspend_equivalent_condition() or - // java_suspend_self() via check_and_wait_while_suspended() - - AttachOperation* op = SolarisAttachListener::dequeue(); - - // were we externally suspended while we were waiting? - thread->check_and_wait_while_suspended(); - - return op; -} - - -// Performs initialization at vm startup -// For Solaris we remove any stale .java_pid file which could cause -// an attaching process to think we are ready to receive a door_call -// before we are properly initialized - -void AttachListener::vm_start() { - char fn[PATH_MAX+1]; - struct stat64 st; - int ret; - - int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d", - os::get_temp_directory(), os::current_process_id()); - assert(n < sizeof(fn), "java_pid file name buffer overflow"); - - RESTARTABLE(::stat64(fn, &st), ret); - if (ret == 0) { - ret = ::unlink(fn); - if (ret == -1) { - log_debug(attach)("Failed to remove stale attach pid file at %s", fn); - } - } -} - -int AttachListener::pd_init() { - JavaThread* thread = JavaThread::current(); - ThreadBlockInVM tbivm(thread); - - thread->set_suspend_equivalent(); - // cleared by handle_special_suspend_equivalent_condition() or - // java_suspend_self() - - int ret_code = SolarisAttachListener::init(); - - // were we externally suspended while we were waiting? - thread->check_and_wait_while_suspended(); - - return ret_code; -} - -// Attach Listener is started lazily except in the case when -// +ReduseSignalUsage is used -bool AttachListener::init_at_startup() { - if (ReduceSignalUsage) { - return true; - } else { - return false; - } -} - -bool AttachListener::check_socket_file() { - int ret; - struct stat64 st; - ret = stat64(SolarisAttachListener::door_path(), &st); - if (ret == -1) { // need to restart attach listener. - log_debug(attach)("Door file %s does not exist - Restart Attach Listener", - SolarisAttachListener::door_path()); - - listener_cleanup(); - - // wait to terminate current attach listener instance... - while (AttachListener::transit_state(AL_INITIALIZING, - AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) { - os::naked_yield(); - } - return is_init_trigger(); - } - return false; -} - -// If the file .attach_pid exists in the working directory -// or /tmp then this is the trigger to start the attach mechanism -bool AttachListener::is_init_trigger() { - if (init_at_startup() || is_initialized()) { - return false; // initialized at startup or already initialized - } - char fn[PATH_MAX + 1]; - int ret; - struct stat64 st; - sprintf(fn, ".attach_pid%d", os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); - if (ret == -1) { - log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); - snprintf(fn, sizeof(fn), "%s/.attach_pid%d", - os::get_temp_directory(), os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); - if (ret == -1) { - log_debug(attach)("Failed to find attach file: %s", fn); - } - } - if (ret == 0) { - // simple check to avoid starting the attach mechanism when - // a bogus non-root user creates the file - if (os::Posix::matches_effective_uid_or_root(st.st_uid)) { - init(); - log_trace(attach)("Attach triggered by %s", fn); - return true; - } else { - log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid()); - } - } - return false; -} - -// if VM aborts then detach/cleanup -void AttachListener::abort() { - listener_cleanup(); -} - -void AttachListener::pd_data_dump() { - os::signal_notify(SIGQUIT); -} - -static jint enable_dprobes(AttachOperation* op, outputStream* out) { - const char* probe = op->arg(0); - if (probe == NULL || probe[0] == '\0') { - out->print_cr("No probe specified"); - return JNI_ERR; - } else { - char *end; - long val = strtol(probe, &end, 10); - if (end == probe || val < 0 || val > INT_MAX) { - out->print_cr("invalid probe type"); - return JNI_ERR; - } else { - int probe_typess = (int) val; - DTrace::enable_dprobes(probe_typess); - return JNI_OK; - } - } -} - -// platform specific operations table -static AttachOperationFunctionInfo funcs[] = { - { "enabledprobes", enable_dprobes }, - { NULL, NULL } -}; - -AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) { - int i; - for (i = 0; funcs[i].name != NULL; i++) { - if (strcmp(funcs[i].name, name) == 0) { - return &funcs[i]; - } - } - return NULL; -} - -// Solaris specific global flag set. Currently, we support only -// changing ExtendedDTraceProbes flag. -jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { - const char* name = op->arg(0); - assert(name != NULL, "flag name should not be null"); - bool flag = true; - const char* arg1; - if ((arg1 = op->arg(1)) != NULL) { - char *end; - flag = (strtol(arg1, &end, 10) != 0); - if (arg1 == end) { - out->print_cr("flag value has to be an integer"); - return JNI_ERR; - } - } - - if (strcmp(name, "ExtendedDTraceProbes") == 0) { - DTrace::set_extended_dprobes(flag); - return JNI_OK; - } - - if (strcmp(name, "DTraceMonitorProbes") == 0) { - DTrace::set_monitor_dprobes(flag); - return JNI_OK; - } - - out->print_cr("flag '%s' cannot be changed", name); - return JNI_ERR; -} - -void AttachListener::pd_detachall() { - DTrace::detach_all_clients(); -} diff --git a/src/hotspot/os/solaris/c1_globals_solaris.hpp b/src/hotspot/os/solaris/c1_globals_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/c1_globals_solaris.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP -#define OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" - -// -// Sets the default values for operating system dependent flags used by the -// client compiler. (see c1_globals.hpp) -// - -#endif // OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP diff --git a/src/hotspot/os/solaris/c2_globals_solaris.hpp b/src/hotspot/os/solaris/c2_globals_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/c2_globals_solaris.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP -#define OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP - -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" - -// -// Sets the default values for operating system dependent flags used by the -// server compiler. (see c2_globals.hpp) -// - -#endif // OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP diff --git a/src/hotspot/os/solaris/decoder_solaris.cpp b/src/hotspot/os/solaris/decoder_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/decoder_solaris.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "utilities/decoder_elf.hpp" - -#include - -bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { - return !cplus_demangle(symbol, buf, (size_t)buflen); -} - diff --git a/src/hotspot/os/solaris/dtrace/jhelper.d b/src/hotspot/os/solaris/dtrace/jhelper.d deleted file mode 100644 --- a/src/hotspot/os/solaris/dtrace/jhelper.d +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (c) 2003, 2018, 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. - * - */ - -/* This file is auto-generated */ -#include "JvmOffsetsIndex.h" - -#define DEBUG - -#ifdef DEBUG -#define MARK_LINE this->line = __LINE__ -#else -#define MARK_LINE -#endif - -#ifdef _LP64 -#define STACK_BIAS 0x7ff -#define pointer uint64_t -#else -#define STACK_BIAS 0 -#define pointer uint32_t -#endif - -extern pointer __JvmOffsets; - -/* GrowableArray* */ -extern pointer __1cJCodeCacheG_heaps_; - -extern pointer __1cIUniverseO_collectedHeap_; - -extern pointer __1cHnmethodG__vtbl_; -extern pointer __1cGMethodG__vtbl_; -extern pointer __1cKBufferBlobG__vtbl_; - -#define copyin_ptr(ADDR) *(pointer*) copyin((pointer) (ADDR), sizeof(pointer)) -#define copyin_uchar(ADDR) *(uchar_t*) copyin((pointer) (ADDR), sizeof(uchar_t)) -#define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t)) -#define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t)) -#define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t)) -#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t)) - -#define copyin_offset(JVM_CONST) JVM_CONST = \ - copyin_int32(JvmOffsetsPtr + IDX_##JVM_CONST * sizeof(int32_t)) - -int init_done; - -dtrace:helper:ustack: -{ - MARK_LINE; - this->done = 0; - /* - * TBD: - * Here we initialize init_done, otherwise jhelper does not work. - * Therefore, copyin_offset() statements work multiple times now. - * There is a hope we could avoid it in the future, and so, - * this initialization can be removed. - */ - init_done = 0; - this->error = (char *) NULL; - this->result = (char *) NULL; - this->isMethod = 0; - this->codecache = 0; - this->klass = (pointer) NULL; - this->vtbl = (pointer) NULL; - this->suffix = '\0'; -} - -dtrace:helper:ustack: -{ - MARK_LINE; - /* Initialization of JvmOffsets constants */ - JvmOffsetsPtr = (pointer) &``__JvmOffsets; -} - -dtrace:helper:ustack: -/!init_done && !this->done/ -{ - MARK_LINE; - - copyin_offset(POINTER_SIZE); - copyin_offset(COMPILER); - copyin_offset(OFFSET_CollectedHeap_reserved); - copyin_offset(OFFSET_MemRegion_start); - copyin_offset(OFFSET_MemRegion_word_size); - copyin_offset(SIZE_HeapWord); - - copyin_offset(OFFSET_interpreter_frame_method); - copyin_offset(OFFSET_Klass_name); - copyin_offset(OFFSET_ConstantPool_pool_holder); - - copyin_offset(OFFSET_HeapBlockHeader_used); - copyin_offset(OFFSET_oopDesc_metadata); - - copyin_offset(OFFSET_Symbol_length); - copyin_offset(OFFSET_Symbol_body); - - copyin_offset(OFFSET_Method_constMethod); - copyin_offset(OFFSET_ConstMethod_constants); - copyin_offset(OFFSET_ConstMethod_name_index); - copyin_offset(OFFSET_ConstMethod_signature_index); - - copyin_offset(OFFSET_CodeHeap_memory); - copyin_offset(OFFSET_CodeHeap_segmap); - copyin_offset(OFFSET_CodeHeap_log2_segment_size); - - copyin_offset(OFFSET_GrowableArray_CodeHeap_data); - copyin_offset(OFFSET_GrowableArray_CodeHeap_len); - - copyin_offset(OFFSET_VirtualSpace_low); - copyin_offset(OFFSET_VirtualSpace_high); - - copyin_offset(OFFSET_CodeBlob_name); - - copyin_offset(OFFSET_nmethod_method); - copyin_offset(SIZE_HeapBlockHeader); - copyin_offset(SIZE_oopDesc); - copyin_offset(SIZE_ConstantPool); - - copyin_offset(OFFSET_NarrowPtrStruct_base); - copyin_offset(OFFSET_NarrowPtrStruct_shift); - - /* - * The PC to translate is in arg0. - */ - this->pc = arg0; - - /* - * The methodPtr is in %l2 on SPARC. This can be found at - * offset 8 from the frame pointer on 32-bit processes. - */ -#if defined(__sparc) - this->methodPtr = copyin_ptr(arg1 + 2 * sizeof(pointer) + STACK_BIAS); -#elif defined(__i386) || defined(__amd64) - this->methodPtr = copyin_ptr(arg1 + OFFSET_interpreter_frame_method); -#else -#error "Don't know architecture" -#endif - - /* Read address of GrowableArray */ - // this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_); - this->code_heaps_address = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cJCodeCacheG_heaps_ ) , sizeof ( uint64_t ) ); - - /* Read address of _data array field in GrowableArray */ - this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data); - this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len); - - this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_; - - /* - * Get Java heap bounds - */ - // this->Universe_collectedHeap = copyin_ptr(&``__1cIUniverseO_collectedHeap_); - this->Universe_collectedHeap = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cIUniverseO_collectedHeap_ ) , sizeof ( uint64_t ) ); - - this->heap_start = copyin_ptr(this->Universe_collectedHeap + - OFFSET_CollectedHeap_reserved + - OFFSET_MemRegion_start); - this->heap_size = SIZE_HeapWord * - copyin_ptr(this->Universe_collectedHeap + - OFFSET_CollectedHeap_reserved + - OFFSET_MemRegion_word_size - ); - this->heap_end = this->heap_start + this->heap_size; -} - -/* - * IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in - * the code cache. If more code heaps are added the following probes have to - * be extended. This is done by simply adding a probe to get the heap bounds - * and another probe to set the code heap address of the newly created heap. - */ - -/* - * ----- BEGIN: Get bounds of code heaps ----- - */ -dtrace:helper:ustack: -/init_done < 1 && this->number_of_heaps >= 1 && !this->done/ -{ - MARK_LINE; - /* CodeHeap 1 */ - init_done = 1; - this->code_heap1_address = copyin_ptr(this->code_heaps_array_address); - this->code_heap1_low = copyin_ptr(this->code_heap1_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); - this->code_heap1_high = copyin_ptr(this->code_heap1_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); -} - -dtrace:helper:ustack: -/init_done < 2 && this->number_of_heaps >= 2 && !this->done/ -{ - MARK_LINE; - /* CodeHeap 2 */ - init_done = 2; - this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; - this->code_heap2_address = copyin_ptr(this->code_heaps_array_address); - this->code_heap2_low = copyin_ptr(this->code_heap2_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); - this->code_heap2_high = copyin_ptr(this->code_heap2_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); -} - -dtrace:helper:ustack: -/init_done < 3 && this->number_of_heaps >= 3 && !this->done/ -{ - /* CodeHeap 3 */ - init_done = 3; - this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; - this->code_heap3_address = copyin_ptr(this->code_heaps_array_address); - this->code_heap3_low = copyin_ptr(this->code_heap3_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); - this->code_heap3_high = copyin_ptr(this->code_heap3_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); -} - -dtrace:helper:ustack: -/init_done < 4 && this->number_of_heaps >= 4 && !this->done/ -{ - /* CodeHeap 4 */ - init_done = 4; - this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; - this->code_heap4_address = copyin_ptr(this->code_heaps_array_address); - this->code_heap4_low = copyin_ptr(this->code_heap4_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); - this->code_heap4_high = copyin_ptr(this->code_heap4_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); -} - -dtrace:helper:ustack: -/init_done < 5 && this->number_of_heaps >= 5 && !this->done/ -{ - /* CodeHeap 5 */ - init_done = 5; - this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; - this->code_heap5_address = copyin_ptr(this->code_heaps_array_address); - this->code_heap5_low = copyin_ptr(this->code_heap5_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); - this->code_heap5_high = copyin_ptr(this->code_heap5_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); -} -/* - * ----- END: Get bounds of code heaps ----- - */ - -/* - * ----- BEGIN: Get address of the code heap pc points to ----- - */ -dtrace:helper:ustack: -/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/ -{ - MARK_LINE; - this->codecache = 1; - this->code_heap_address = this->code_heap1_address; -} - -dtrace:helper:ustack: -/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/ -{ - MARK_LINE; - this->codecache = 1; - this->code_heap_address = this->code_heap2_address; -} - -dtrace:helper:ustack: -/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/ -{ - MARK_LINE; - this->codecache = 1; - this->code_heap_address = this->code_heap3_address; -} - -dtrace:helper:ustack: -/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/ -{ - MARK_LINE; - this->codecache = 1; - this->code_heap_address = this->code_heap4_address; -} - -dtrace:helper:ustack: -/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/ -{ - MARK_LINE; - this->codecache = 1; - this->code_heap_address = this->code_heap5_address; -} -/* - * ----- END: Get address of the code heap pc points to ----- - */ - -dtrace:helper:ustack: -/!this->done && this->codecache/ -{ - MARK_LINE; - /* - * Get code heap configuration - */ - this->code_heap_low = copyin_ptr(this->code_heap_address + - OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); - this->code_heap_segmap_low = copyin_ptr(this->code_heap_address + - OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low); - this->code_heap_log2_segment_size = copyin_uint32( - this->code_heap_address + OFFSET_CodeHeap_log2_segment_size); - - /* - * Find start - */ - this->segment = (this->pc - this->code_heap_low) >> - this->code_heap_log2_segment_size; - this->block = this->code_heap_segmap_low; - this->tag = copyin_uchar(this->block + this->segment); -} - -dtrace:helper:ustack: -/!this->done && this->codecache && this->tag > 0/ -{ - MARK_LINE; - this->tag = copyin_uchar(this->block + this->segment); - this->segment = this->segment - this->tag; -} - -dtrace:helper:ustack: -/!this->done && this->codecache && this->tag > 0/ -{ - MARK_LINE; - this->tag = copyin_uchar(this->block + this->segment); - this->segment = this->segment - this->tag; -} - -dtrace:helper:ustack: -/!this->done && this->codecache && this->tag > 0/ -{ - MARK_LINE; - this->tag = copyin_uchar(this->block + this->segment); - this->segment = this->segment - this->tag; -} - -dtrace:helper:ustack: -/!this->done && this->codecache && this->tag > 0/ -{ - MARK_LINE; - this->tag = copyin_uchar(this->block + this->segment); - this->segment = this->segment - this->tag; -} - -dtrace:helper:ustack: -/!this->done && this->codecache && this->tag > 0/ -{ - MARK_LINE; - this->tag = copyin_uchar(this->block + this->segment); - this->segment = this->segment - this->tag; -} - -dtrace:helper:ustack: -/!this->done && this->codecache && this->tag > 0/ -{ - MARK_LINE; - this->error = ""; - this->done = 1; -} - -dtrace:helper:ustack: -/!this->done && this->codecache/ -{ - MARK_LINE; - this->block = this->code_heap_low + - (this->segment << this->code_heap_log2_segment_size); - this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used); -} - -dtrace:helper:ustack: -/!this->done && this->codecache && !this->used/ -{ - MARK_LINE; - this->error = ""; - this->done = 1; -} - -dtrace:helper:ustack: -/!this->done && this->codecache/ -{ - MARK_LINE; - this->start = this->block + SIZE_HeapBlockHeader; - this->vtbl = copyin_ptr(this->start); - - this->nmethod_vtbl = (pointer) &``__1cHnmethodG__vtbl_; - this->BufferBlob_vtbl = (pointer) &``__1cKBufferBlobG__vtbl_; -} - -dtrace:helper:ustack: -/!this->done && this->vtbl == this->nmethod_vtbl/ -{ - MARK_LINE; - this->methodPtr = copyin_ptr(this->start + OFFSET_nmethod_method); - this->suffix = '*'; - this->isMethod = 1; -} - -dtrace:helper:ustack: -/!this->done && this->vtbl == this->BufferBlob_vtbl/ -{ - MARK_LINE; - this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name); -} - - -dtrace:helper:ustack: -/!this->done && this->vtbl == this->BufferBlob_vtbl && this->methodPtr != 0/ -{ - MARK_LINE; - this->klass = copyin_ptr(this->methodPtr); - this->isMethod = this->klass == this->Method_vtbl; - this->done = !this->isMethod; -} - -dtrace:helper:ustack: -/!this->done && !this->isMethod/ -{ - MARK_LINE; - this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name); - this->result = this->name != 0 ? copyinstr(this->name) : ""; - this->done = 1; -} - -dtrace:helper:ustack: -/!this->done && this->isMethod/ -{ - MARK_LINE; - this->constMethod = copyin_ptr(this->methodPtr + - OFFSET_Method_constMethod); - - this->nameIndex = copyin_uint16(this->constMethod + - OFFSET_ConstMethod_name_index); - - this->signatureIndex = copyin_uint16(this->constMethod + - OFFSET_ConstMethod_signature_index); - - this->constantPool = copyin_ptr(this->constMethod + - OFFSET_ConstMethod_constants); - - this->nameSymbol = copyin_ptr(this->constantPool + - this->nameIndex * sizeof (pointer) + SIZE_ConstantPool); - /* The symbol is a CPSlot and has lower bit set to indicate metadata */ - this->nameSymbol &= (~1); /* remove metadata lsb */ - - this->nameSymbolLength = copyin_uint16(this->nameSymbol + - OFFSET_Symbol_length); - - this->signatureSymbol = copyin_ptr(this->constantPool + - this->signatureIndex * sizeof (pointer) + SIZE_ConstantPool); - this->signatureSymbol &= (~1); /* remove metadata lsb */ - - this->signatureSymbolLength = copyin_uint16(this->signatureSymbol + - OFFSET_Symbol_length); - - this->klassPtr = copyin_ptr(this->constantPool + - OFFSET_ConstantPool_pool_holder); - - this->klassSymbol = copyin_ptr(this->klassPtr + - OFFSET_Klass_name); - - this->klassSymbolLength = copyin_uint16(this->klassSymbol + - OFFSET_Symbol_length); - - /* - * Enough for three strings, plus the '.', plus the trailing '\0'. - */ - this->result = (char *) alloca(this->klassSymbolLength + - this->nameSymbolLength + - this->signatureSymbolLength + 2 + 1); - - copyinto(this->klassSymbol + OFFSET_Symbol_body, - this->klassSymbolLength, this->result); - - /* - * Add the '.' between the class and the name. - */ - this->result[this->klassSymbolLength] = '.'; - - copyinto(this->nameSymbol + OFFSET_Symbol_body, - this->nameSymbolLength, - this->result + this->klassSymbolLength + 1); - - copyinto(this->signatureSymbol + OFFSET_Symbol_body, - this->signatureSymbolLength, - this->result + this->klassSymbolLength + - this->nameSymbolLength + 1); - - /* - * Now we need to add a trailing '\0' and possibly a tag character. - */ - this->result[this->klassSymbolLength + 1 + - this->nameSymbolLength + - this->signatureSymbolLength] = this->suffix; - this->result[this->klassSymbolLength + 2 + - this->nameSymbolLength + - this->signatureSymbolLength] = '\0'; - - this->done = 1; -} - -dtrace:helper:ustack: -/this->done && this->error == (char *) NULL/ -{ - this->result; -} - -dtrace:helper:ustack: -/this->done && this->error != (char *) NULL/ -{ - this->error; -} - -dtrace:helper:ustack: -/!this->done && this->codecache/ -{ - this->done = 1; - "error"; -} - - -dtrace:helper:ustack: -/!this->done/ -{ - NULL; -} diff --git a/src/hotspot/os/solaris/globals_solaris.hpp b/src/hotspot/os/solaris/globals_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/globals_solaris.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2005, 2020, 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. - * - */ - -#ifndef OS_SOLARIS_GLOBALS_SOLARIS_HPP -#define OS_SOLARIS_GLOBALS_SOLARIS_HPP - -// -// Defines Solaris specific flags. They are not available on other platforms. -// -#define RUNTIME_OS_FLAGS(develop, \ - develop_pd, \ - product, \ - product_pd, \ - diagnostic, \ - diagnostic_pd, \ - notproduct, \ - range, \ - constraint) \ - \ - product(bool, UseExtendedFileIO, true, \ - "Enable workaround for limitations of stdio FILE structure") - -// -// Defines Solaris-specific default values. The flags are available on all -// platforms, but they may have different default values on other platforms. -// -define_pd_global(bool, UseLargePages, true); -define_pd_global(bool, UseLargePagesIndividualAllocation, false); -define_pd_global(bool, UseOSErrorReporting, false); -define_pd_global(bool, UseThreadPriorities, false); - -#endif // OS_SOLARIS_GLOBALS_SOLARIS_HPP diff --git a/src/hotspot/os/solaris/osThread_solaris.cpp b/src/hotspot/os/solaris/osThread_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/osThread_solaris.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 1998, 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. - * - */ - -// no precompiled headers -#include "runtime/handles.inline.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/os.hpp" -#include "runtime/osThread.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/vmThread.hpp" - -#include - - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - -void OSThread::pd_initialize() { - _thread_id = 0; - sigemptyset(&_caller_sigmask); - - _vm_created_thread = false; -} - -void OSThread::pd_destroy() { -} - -// copied from synchronizer.cpp - -void OSThread::SR_handler(Thread* thread, ucontext_t* uc) { - os::Solaris::SR_handler(thread, uc); -} diff --git a/src/hotspot/os/solaris/osThread_solaris.hpp b/src/hotspot/os/solaris/osThread_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/osThread_solaris.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef OS_SOLARIS_OSTHREAD_SOLARIS_HPP -#define OS_SOLARIS_OSTHREAD_SOLARIS_HPP - -// This is embedded via include into the class OSThread - public: - typedef thread_t thread_id_t; - - private: - uint _lwp_id; // lwp ID, only used with bound threads - int _native_priority; // Saved native priority when starting - // a bound thread - sigset_t _caller_sigmask; // Caller's signal mask - bool _vm_created_thread; // true if the VM created this thread, - // false if primary thread or attached thread - public: - uint lwp_id() const { return _lwp_id; } - int native_priority() const { return _native_priority; } - - // Set and get state of _vm_created_thread flag - void set_vm_created() { _vm_created_thread = true; } - bool is_vm_created() { return _vm_created_thread; } - - // Methods to save/restore caller's signal mask - sigset_t caller_sigmask() const { return _caller_sigmask; } - void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } - -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif -#ifdef ASSERT - // On solaris reposition can fail in two ways: - // 1: a mismatched pc, because signal is delivered too late, target thread - // is resumed. - // 2: on a timeout where signal is lost, target thread is resumed. - bool valid_reposition_failure() { - // only 1 and 2 can happen and we can handle both of them - return true; - } -#endif - void set_lwp_id(uint id) { _lwp_id = id; } - void set_native_priority(int prio) { _native_priority = prio; } - - public: - os::SuspendResume sr; - - private: - ucontext_t* _ucontext; - - public: - ucontext_t* ucontext() const { return _ucontext; } - void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; } - static void SR_handler(Thread* thread, ucontext_t* uc); - - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - -private: - - void pd_initialize(); - void pd_destroy(); - -#endif // OS_SOLARIS_OSTHREAD_SOLARIS_HPP diff --git a/src/hotspot/os/solaris/os_perf_solaris.cpp b/src/hotspot/os/solaris/os_perf_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/os_perf_solaris.cpp +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Copyright (c) 2012, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "jvm.h" -#include "memory/allocation.inline.hpp" -#include "runtime/os.hpp" -#include "runtime/os_perf.hpp" -#include "os_solaris.inline.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" - -#include CPU_HEADER(vm_version_ext) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const double NANOS_PER_SEC = 1000000000.0; - -struct CPUPerfTicks { - kstat_t* kstat; - uint64_t last_idle; - uint64_t last_total; - double last_ratio; -}; - -struct CPUPerfCounters { - int nProcs; - CPUPerfTicks* jvmTicks; - kstat_ctl_t* kstat_ctrl; -}; - -static int get_info(const char* path, void* info, size_t s, off_t o) { - assert(path != NULL, "path is NULL!"); - assert(info != NULL, "info is NULL!"); - - int fd = -1; - - if ((fd = os::open(path, O_RDONLY, 0)) < 0) { - return OS_ERR; - } - if (pread(fd, info, s, o) != s) { - close(fd); - return OS_ERR; - } - close(fd); - return OS_OK; -} - -static int get_psinfo2(void* info, size_t s, off_t o) { - return get_info("/proc/self/psinfo", info, s, o); -} - -static int get_psinfo(psinfo_t* info) { - return get_psinfo2(info, sizeof(*info), 0); -} - -static int get_psinfo(char* file, psinfo_t* info) { - assert(file != NULL, "file is NULL!"); - assert(info != NULL, "info is NULL!"); - return get_info(file, info, sizeof(*info), 0); -} - - -static int get_usage(prusage_t* usage) { - assert(usage != NULL, "usage is NULL!"); - return get_info("/proc/self/usage", usage, sizeof(*usage), 0); -} - -static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) { - assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!"); - assert(load != NULL, "load pointer is NULL!"); - assert(cpu_stat != NULL, "cpu_stat pointer is NULL!"); - - if (load->kstat == NULL) { - // no handle. - return OS_ERR; - } - if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) { - // disable handle for this CPU - load->kstat = NULL; - return OS_ERR; - } - return OS_OK; -} - -static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) { - assert(counters != NULL, "counters pointer is NULL!"); - - cpu_stat_t cpu_stat = {0}; - - if (which_logical_cpu >= counters->nProcs) { - return .0; - } - - CPUPerfTicks load = counters->jvmTicks[which_logical_cpu]; - if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) { - return .0; - } - - uint_t* usage = cpu_stat.cpu_sysinfo.cpu; - if (usage == NULL) { - return .0; - } - - uint64_t c_idle = usage[CPU_IDLE]; - uint64_t c_total = 0; - - for (int i = 0; i < CPU_STATES; i++) { - c_total += usage[i]; - } - - // Calculate diff against previous snapshot - uint64_t d_idle = c_idle - load.last_idle; - uint64_t d_total = c_total - load.last_total; - - /** update if weve moved */ - if (d_total > 0) { - // Save current values for next time around - load.last_idle = c_idle; - load.last_total = c_total; - load.last_ratio = (double) (d_total - d_idle) / d_total; - } - - return load.last_ratio; -} - -static int get_boot_time(uint64_t* time) { - assert(time != NULL, "time pointer is NULL!"); - setutxent(); - for(;;) { - struct utmpx* u; - if ((u = getutxent()) == NULL) { - break; - } - if (u->ut_type == BOOT_TIME) { - *time = u->ut_xtime; - endutxent(); - return OS_OK; - } - } - endutxent(); - return OS_ERR; -} - -static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) { - assert(switches != NULL, "switches pointer is NULL!"); - assert(counters != NULL, "counter pointer is NULL!"); - *switches = 0; - uint64_t s = 0; - - // Collect data from all CPUs - for (int i = 0; i < counters->nProcs; i++) { - cpu_stat_t cpu_stat = {0}; - CPUPerfTicks load = counters->jvmTicks[i]; - - if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) { - s += cpu_stat.cpu_sysinfo.pswitch; - } else { - //fail fast... - return OS_ERR; - } - } - *switches = s; - return OS_OK; -} - -static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) { - assert(counters != NULL, "counters is NULL!"); - assert(rate != NULL, "rate pointer is NULL!"); - static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; - static uint64_t lastTime = 0; - static uint64_t lastSwitches = 0; - static double lastRate = 0.0; - - uint64_t lt = 0; - int res = 0; - - if (lastTime == 0) { - uint64_t tmp; - if (get_boot_time(&tmp) < 0) { - return OS_ERR; - } - lt = tmp * 1000; - } - - res = OS_OK; - - pthread_mutex_lock(&contextSwitchLock); - { - - uint64_t sw = 0; - clock_t t, d; - - if (lastTime == 0) { - lastTime = lt; - } - - t = clock(); - d = t - lastTime; - - if (d == 0) { - *rate = lastRate; - } else if (get_noof_context_switches(counters, &sw)== OS_OK) { - *rate = ((double)(sw - lastSwitches) / d) * 1000; - lastRate = *rate; - lastSwitches = sw; - lastTime = t; - } else { - *rate = 0.0; - res = OS_ERR; - } - if (*rate < 0.0) { - *rate = 0.0; - lastRate = 0.0; - } - } - pthread_mutex_unlock(&contextSwitchLock); - return res; - } - - - -class CPUPerformanceInterface::CPUPerformance : public CHeapObj { - friend class CPUPerformanceInterface; - private: - CPUPerfCounters _counters; - int cpu_load(int which_logical_cpu, double* cpu_load); - int context_switch_rate(double* rate); - int cpu_load_total_process(double* cpu_load); - int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); - - CPUPerformance(); - ~CPUPerformance(); - bool initialize(); -}; - -CPUPerformanceInterface::CPUPerformance::CPUPerformance() { - _counters.nProcs = 0; - _counters.jvmTicks = NULL; - _counters.kstat_ctrl = NULL; -} - -bool CPUPerformanceInterface::CPUPerformance::initialize() { - // initialize kstat control structure, - _counters.kstat_ctrl = kstat_open(); - assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!"); - - if (NULL == _counters.kstat_ctrl) { - return false; - } - - // Get number of CPU(s) - if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) { - // ignore error? - _counters.nProcs = 1; - } - - assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!"); - if (_counters.nProcs == 0) { - return false; - } - - // Data structure(s) for saving CPU load (one per CPU) - size_t array_entry_count = _counters.nProcs; - _counters.jvmTicks = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal); - memset(_counters.jvmTicks, 0, array_entry_count * sizeof(*_counters.jvmTicks)); - - // Get kstat cpu_stat counters for every CPU - // loop over kstat to find our cpu_stat(s) - int i = 0; - for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { - if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { - if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) { - continue; - } - if (i == _counters.nProcs) { - // more cpu_stats than reported CPUs - break; - } - _counters.jvmTicks[i++].kstat = kstat; - } - } - return true; -} - -CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { - FREE_C_HEAP_ARRAY(char, _counters.jvmTicks); - if (_counters.kstat_ctrl != NULL) { - kstat_close(_counters.kstat_ctrl); - } -} - -int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { - assert(cpu_load != NULL, "cpu_load pointer is NULL!"); - double t = .0; - if (-1 == which_logical_cpu) { - for (int i = 0; i < _counters.nProcs; i++) { - t += get_cpu_load(i, &_counters); - } - // Cap total systemload to 1.0 - t = MIN2((t / _counters.nProcs), 1.0); - } else { - t = MIN2(get_cpu_load(which_logical_cpu, &_counters), 1.0); - } - - *cpu_load = t; - return OS_OK; -} - -int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { - assert(cpu_load != NULL, "cpu_load pointer is NULL!"); - - psinfo_t info; - - // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s - // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000. - if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) { - *cpu_load = 0.0; - return OS_ERR; - } - *cpu_load = (double) info.pr_pctcpu / 0x8000; - return OS_OK; -} - -int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { - assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited"); - assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited"); - assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited"); - - static uint64_t lastTime; - static uint64_t lastUser, lastKernel; - static double lastUserRes, lastKernelRes; - - pstatus_t pss; - psinfo_t info; - - *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0; - if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) { - return OS_ERR; - } - - if (get_psinfo(&info) != 0) { - return OS_ERR; - } - - // get the total time in user, kernel and total time - // check ratios for 'lately' and multiply the 'recent load'. - uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec; - uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec; - uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec; - uint64_t diff = time - lastTime; - double load = (double) info.pr_pctcpu / 0x8000; - - if (diff > 0) { - lastUserRes = (load * (user - lastUser)) / diff; - lastKernelRes = (load * (kernel - lastKernel)) / diff; - - // BUG9182835 - patch for clamping these values to sane ones. - lastUserRes = MIN2(1, lastUserRes); - lastUserRes = MAX2(0, lastUserRes); - lastKernelRes = MIN2(1, lastKernelRes); - lastKernelRes = MAX2(0, lastKernelRes); - } - - double t = .0; - cpu_load(-1, &t); - // clamp at user+system and 1.0 - if (lastUserRes + lastKernelRes > t) { - t = MIN2(lastUserRes + lastKernelRes, 1.0); - } - - *pjvmUserLoad = lastUserRes; - *pjvmKernelLoad = lastKernelRes; - *psystemTotalLoad = t; - - lastTime = time; - lastUser = user; - lastKernel = kernel; - - return OS_OK; -} - -int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { - return perf_context_switch_rate(&_counters, rate); -} - -CPUPerformanceInterface::CPUPerformanceInterface() { - _impl = NULL; -} - -bool CPUPerformanceInterface::initialize() { - _impl = new CPUPerformanceInterface::CPUPerformance(); - return _impl->initialize(); -} - -CPUPerformanceInterface::~CPUPerformanceInterface(void) { - if (_impl != NULL) { - delete _impl; - } -} - -int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { - return _impl->cpu_load(which_logical_cpu, cpu_load); -} - -int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { - return _impl->cpu_load_total_process(cpu_load); -} - -int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const { - return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); -} - -int CPUPerformanceInterface::context_switch_rate(double* rate) const { - return _impl->context_switch_rate(rate); -} - -class SystemProcessInterface::SystemProcesses : public CHeapObj { - friend class SystemProcessInterface; - private: - class ProcessIterator : public CHeapObj { - friend class SystemProcessInterface::SystemProcesses; - private: - DIR* _dir; - struct dirent* _entry; - bool _valid; - - ProcessIterator(); - ~ProcessIterator(); - bool initialize(); - - bool is_valid() const { return _valid; } - bool is_valid_entry(struct dirent* const entry) const; - bool is_dir(const char* const name) const; - char* allocate_string(const char* const str) const; - int current(SystemProcess* const process_info); - int next_process(); - }; - - ProcessIterator* _iterator; - SystemProcesses(); - bool initialize(); - ~SystemProcesses(); - - //information about system processes - int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; -}; - -bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const { - struct stat64 mystat; - int ret_val = 0; - - ret_val = ::stat64(name, &mystat); - - if (ret_val < 0) { - return false; - } - ret_val = S_ISDIR(mystat.st_mode); - return ret_val > 0; -} - -// if it has a numeric name, is a directory and has a 'psinfo' file in it -bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const { - // ignore the "." and ".." directories - if ((strcmp(entry->d_name, ".") == 0) || - (strcmp(entry->d_name, "..") == 0)) { - return false; - } - - char buffer[PATH_MAX] = {0}; - uint64_t size = 0; - bool result = false; - FILE *fp = NULL; - - if (atoi(entry->d_name) != 0) { - jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name); - - if (is_dir(buffer)) { - memset(buffer, 0, PATH_MAX); - jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name); - if ((fp = fopen(buffer, "r")) != NULL) { - int nread = 0; - psinfo_t psinfo_data; - if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) { - // only considering system process owned by root - if (psinfo_data.pr_uid == 0) { - result = true; - } - } - } - } - } - - if (fp != NULL) { - fclose(fp); - } - - return result; -} - -char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { - if (str != NULL) { - return os::strdup_check_oom(str, mtInternal); - } - return NULL; -} - -int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { - if (!is_valid()) { - return OS_ERR; - } - - char psinfo_path[PATH_MAX] = {0}; - jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name); - - FILE *fp = NULL; - if ((fp = fopen(psinfo_path, "r")) == NULL) { - return OS_ERR; - } - - int nread = 0; - psinfo_t psinfo_data; - if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) { - fclose(fp); - return OS_ERR; - } - - char *exe_path = NULL; - if ((psinfo_data.pr_fname != NULL) && - (psinfo_data.pr_psargs != NULL)) { - char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname); - if (path_substring != NULL) { - int len = path_substring - psinfo_data.pr_psargs; - exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal); - jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs); - exe_path[len] = '\0'; - } - } - - process_info->set_pid(atoi(_entry->d_name)); - process_info->set_name(allocate_string(psinfo_data.pr_fname)); - process_info->set_path(allocate_string(exe_path)); - process_info->set_command_line(allocate_string(psinfo_data.pr_psargs)); - - if (exe_path != NULL) { - FREE_C_HEAP_ARRAY(char, exe_path); - } - - if (fp != NULL) { - fclose(fp); - } - - return OS_OK; -} - -int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { - if (!is_valid()) { - return OS_ERR; - } - - do { - _entry = os::readdir(_dir); - if (_entry == NULL) { - // Error or reached end. Could use errno to distinguish those cases. - _valid = false; - return OS_ERR; - } - } while(!is_valid_entry(_entry)); - - _valid = true; - return OS_OK; -} - -SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { - _dir = NULL; - _entry = NULL; - _valid = false; -} - -bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { - _dir = os::opendir("/proc"); - _entry = NULL; - _valid = true; - next_process(); - - return true; -} - -SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { - if (_dir != NULL) { - os::closedir(_dir); - } -} - -SystemProcessInterface::SystemProcesses::SystemProcesses() { - _iterator = NULL; -} - -bool SystemProcessInterface::SystemProcesses::initialize() { - _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); - return _iterator->initialize(); -} - -SystemProcessInterface::SystemProcesses::~SystemProcesses() { - if (_iterator != NULL) { - delete _iterator; - } -} - -int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { - assert(system_processes != NULL, "system_processes pointer is NULL!"); - assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!"); - assert(_iterator != NULL, "iterator is NULL!"); - - // initialize pointers - *no_of_sys_processes = 0; - *system_processes = NULL; - - while (_iterator->is_valid()) { - SystemProcess* tmp = new SystemProcess(); - _iterator->current(tmp); - - //if already existing head - if (*system_processes != NULL) { - //move "first to second" - tmp->set_next(*system_processes); - } - // new head - *system_processes = tmp; - // increment - (*no_of_sys_processes)++; - // step forward - _iterator->next_process(); - } - return OS_OK; -} - -int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const { - return _impl->system_processes(system_procs, no_of_sys_processes); -} - -SystemProcessInterface::SystemProcessInterface() { - _impl = NULL; -} - -bool SystemProcessInterface::initialize() { - _impl = new SystemProcessInterface::SystemProcesses(); - return _impl->initialize(); - -} - -SystemProcessInterface::~SystemProcessInterface() { - if (_impl != NULL) { - delete _impl; - } -} - -CPUInformationInterface::CPUInformationInterface() { - _cpu_info = NULL; -} - -bool CPUInformationInterface::initialize() { - _cpu_info = new CPUInformation(); - _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads()); - _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores()); - _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets()); - _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name()); - _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description()); - return true; -} - -CPUInformationInterface::~CPUInformationInterface() { - if (_cpu_info != NULL) { - if (_cpu_info->cpu_name() != NULL) { - const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); - _cpu_info->set_cpu_name(NULL); - } - if (_cpu_info->cpu_description() != NULL) { - const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); - _cpu_info->set_cpu_description(NULL); - } - delete _cpu_info; - } -} - -int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { - if (_cpu_info == NULL) { - return OS_ERR; - } - - cpu_info = *_cpu_info; // shallow copy assignment - return OS_OK; -} - -class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { - friend class NetworkPerformanceInterface; - private: - NetworkPerformance(); - NONCOPYABLE(NetworkPerformance); - bool initialize(); - ~NetworkPerformance(); - int network_utilization(NetworkInterface** network_interfaces) const; -}; - -NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { - -} - -bool NetworkPerformanceInterface::NetworkPerformance::initialize() { - return true; -} - -NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { - -} - -int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const -{ - kstat_ctl_t* ctl = kstat_open(); - if (ctl == NULL) { - return OS_ERR; - } - - NetworkInterface* ret = NULL; - for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) { - if (strcmp(k->ks_class, "net") != 0) { - continue; - } - if (strcmp(k->ks_module, "link") != 0) { - continue; - } - - if (kstat_read(ctl, k, NULL) == -1) { - return OS_ERR; - } - - uint64_t bytes_in = UINT64_MAX; - uint64_t bytes_out = UINT64_MAX; - for (int i = 0; i < k->ks_ndata; ++i) { - kstat_named_t* data = &reinterpret_cast(k->ks_data)[i]; - if (strcmp(data->name, "rbytes64") == 0) { - bytes_in = data->value.ui64; - } - else if (strcmp(data->name, "obytes64") == 0) { - bytes_out = data->value.ui64; - } - } - - if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) { - NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret); - ret = cur; - } - } - - kstat_close(ctl); - *network_interfaces = ret; - - return OS_OK; -} - -NetworkPerformanceInterface::NetworkPerformanceInterface() { - _impl = NULL; -} - -NetworkPerformanceInterface::~NetworkPerformanceInterface() { - if (_impl != NULL) { - delete _impl; - } -} - -bool NetworkPerformanceInterface::initialize() { - _impl = new NetworkPerformanceInterface::NetworkPerformance(); - return _impl->initialize(); -} - -int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { - return _impl->network_utilization(network_interfaces); -} diff --git a/src/hotspot/os/solaris/os_share_solaris.hpp b/src/hotspot/os/solaris/os_share_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/os_share_solaris.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_SOLARIS_OS_SHARE_SOLARIS_HPP -#define OS_SOLARIS_OS_SHARE_SOLARIS_HPP - -// Defines the interfaces to Solaris operating systems that vary across platforms - -// misc -extern "C" { - void signalHandler(int, siginfo_t*, void*); -} -void resolve_lwp_exit_calls(void); -void handle_unexpected_exception(Thread* thread, int sig, siginfo_t* info, address pc, address adjusted_pc); -#ifndef PRODUCT -void continue_with_dump(void); -#endif - -#define PROCFILE_LENGTH 128 - -#endif // OS_SOLARIS_OS_SHARE_SOLARIS_HPP diff --git a/src/hotspot/os/solaris/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/os_solaris.cpp +++ /dev/null @@ -1,5226 +0,0 @@ -/* - * Copyright (c) 1997, 2020, 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. - * - */ - -// no precompiled headers -#include "jvm.h" -#include "classfile/classLoader.hpp" -#include "classfile/systemDictionary.hpp" -#include "classfile/vmSymbols.hpp" -#include "code/icBuffer.hpp" -#include "code/vtableStubs.hpp" -#include "compiler/compileBroker.hpp" -#include "compiler/disassembler.hpp" -#include "interpreter/interpreter.hpp" -#include "logging/log.hpp" -#include "logging/logStream.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/filemap.hpp" -#include "memory/universe.hpp" -#include "oops/oop.inline.hpp" -#include "os_share_solaris.hpp" -#include "os_solaris.inline.hpp" -#include "prims/jniFastGetField.hpp" -#include "prims/jvm_misc.hpp" -#include "runtime/arguments.hpp" -#include "runtime/atomic.hpp" -#include "runtime/extendedPC.hpp" -#include "runtime/globals.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/java.hpp" -#include "runtime/javaCalls.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/objectMonitor.hpp" -#include "runtime/orderAccess.hpp" -#include "runtime/osThread.hpp" -#include "runtime/perfMemory.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/statSampler.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/threadCritical.hpp" -#include "runtime/timer.hpp" -#include "runtime/vm_version.hpp" -#include "semaphore_posix.hpp" -#include "services/attachListener.hpp" -#include "services/memTracker.hpp" -#include "services/runtimeService.hpp" -#include "utilities/align.hpp" -#include "utilities/decoder.hpp" -#include "utilities/defaultStream.hpp" -#include "utilities/events.hpp" -#include "utilities/growableArray.hpp" -#include "utilities/macros.hpp" -#include "utilities/vmError.hpp" - -// put OS-includes here -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include // for elf Sym structure used by dladdr1 -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# define _STRUCTURED_PROC 1 // this gets us the new structured proc interfaces of 5.6 & later -# include // see comment in - -#define MAX_PATH (2 * K) - -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - - -// Here are some liblgrp types from sys/lgrp_user.h to be able to -// compile on older systems without this header file. - -#ifndef MADV_ACCESS_LWP - #define MADV_ACCESS_LWP 7 /* next LWP to access heavily */ -#endif -#ifndef MADV_ACCESS_MANY - #define MADV_ACCESS_MANY 8 /* many processes to access heavily */ -#endif - -#ifndef LGRP_RSRC_CPU - #define LGRP_RSRC_CPU 0 /* CPU resources */ -#endif -#ifndef LGRP_RSRC_MEM - #define LGRP_RSRC_MEM 1 /* memory resources */ -#endif - -// Values for ThreadPriorityPolicy == 1 -int prio_policy1[CriticalPriority+1] = { - -99999, 0, 16, 32, 48, 64, - 80, 96, 112, 124, 127, 127 }; - -// System parameters used internally -static clock_t clock_tics_per_sec = 100; - -// Track if we have called enable_extended_FILE_stdio (on Solaris 10u4+) -static bool enabled_extended_FILE_stdio = false; - -// For diagnostics to print a message once. see run_periodic_checks -static bool check_addr0_done = false; -static sigset_t check_signal_done; -static bool check_signals = true; - -address os::Solaris::handler_start; // start pc of thr_sighndlrinfo -address os::Solaris::handler_end; // end pc of thr_sighndlrinfo - -address os::Solaris::_main_stack_base = NULL; // 4352906 workaround - -os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL; - -// "default" initializers for missing libc APIs -extern "C" { - static int lwp_mutex_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; } - static int lwp_mutex_destroy(mutex_t *mx) { return 0; } - - static int lwp_cond_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; } - static int lwp_cond_destroy(cond_t *cv) { return 0; } -} - -// "default" initializers for pthread-based synchronization -extern "C" { - static int pthread_mutex_default_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; } - static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; } -} - -static void unpackTime(timespec* absTime, bool isAbsolute, jlong time); - -static inline size_t adjust_stack_size(address base, size_t size) { - if ((ssize_t)size < 0) { - // 4759953: Compensate for ridiculous stack size. - size = max_intx; - } - if (size > (size_t)base) { - // 4812466: Make sure size doesn't allow the stack to wrap the address space. - size = (size_t)base; - } - return size; -} - -static inline stack_t get_stack_info() { - stack_t st; - int retval = thr_stksegment(&st); - st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size); - assert(retval == 0, "incorrect return value from thr_stksegment"); - assert((address)&st < (address)st.ss_sp, "Invalid stack base returned"); - assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned"); - return st; -} - -static void _handle_uncaught_cxx_exception() { - VMError::report_and_die("An uncaught C++ exception"); -} - -bool os::is_primordial_thread(void) { - int r = thr_main(); - guarantee(r == 0 || r == 1, "CR6501650 or CR6493689"); - return r == 1; -} - -address os::current_stack_base() { - bool _is_primordial_thread = is_primordial_thread(); - - // Workaround 4352906, avoid calls to thr_stksegment by - // thr_main after the first one (it looks like we trash - // some data, causing the value for ss_sp to be incorrect). - if (!_is_primordial_thread || os::Solaris::_main_stack_base == NULL) { - stack_t st = get_stack_info(); - if (_is_primordial_thread) { - // cache initial value of stack base - os::Solaris::_main_stack_base = (address)st.ss_sp; - } - return (address)st.ss_sp; - } else { - guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base"); - return os::Solaris::_main_stack_base; - } -} - -size_t os::current_stack_size() { - size_t size; - - if (!is_primordial_thread()) { - size = get_stack_info().ss_size; - } else { - struct rlimit limits; - getrlimit(RLIMIT_STACK, &limits); - size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur); - } - // base may not be page aligned - address base = current_stack_base(); - address bottom = align_up(base - size, os::vm_page_size());; - return (size_t)(base - bottom); -} - -struct tm* os::localtime_pd(const time_t* clock, struct tm* res) { - return localtime_r(clock, res); -} - -void os::Solaris::try_enable_extended_io() { - typedef int (*enable_extended_FILE_stdio_t)(int, int); - - if (!UseExtendedFileIO) { - return; - } - - enable_extended_FILE_stdio_t enabler = - (enable_extended_FILE_stdio_t) dlsym(RTLD_DEFAULT, - "enable_extended_FILE_stdio"); - if (enabler) { - enabler(-1, -1); - } -} - -jint os::Solaris::_os_thread_limit = 0; -volatile jint os::Solaris::_os_thread_count = 0; - -julong os::available_memory() { - return Solaris::available_memory(); -} - -julong os::Solaris::available_memory() { - return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size(); -} - -julong os::Solaris::_physical_memory = 0; - -julong os::physical_memory() { - return Solaris::physical_memory(); -} - -static hrtime_t first_hrtime = 0; -static const hrtime_t hrtime_hz = 1000*1000*1000; -static volatile hrtime_t max_hrtime = 0; - - -void os::Solaris::initialize_system_info() { - set_processor_count(sysconf(_SC_NPROCESSORS_CONF)); - _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * - (julong)sysconf(_SC_PAGESIZE); -} - -uint os::processor_id() { - const processorid_t id = ::getcpuid(); - assert(id >= 0 && id < _processor_count, "Invalid processor id"); - return (uint)id; -} - -int os::active_processor_count() { - // User has overridden the number of active processors - if (ActiveProcessorCount > 0) { - log_trace(os)("active_processor_count: " - "active processor count set by user : %d", - ActiveProcessorCount); - return ActiveProcessorCount; - } - - int online_cpus = sysconf(_SC_NPROCESSORS_ONLN); - pid_t pid = getpid(); - psetid_t pset = PS_NONE; - // Are we running in a processor set or is there any processor set around? - if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) { - uint_t pset_cpus; - // Query the number of cpus available to us. - if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) { - assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check"); - return pset_cpus; - } - } - // Otherwise return number of online cpus - return online_cpus; -} - -void os::set_native_thread_name(const char *name) { - if (Solaris::_pthread_setname_np != NULL) { - // Only the first 31 bytes of 'name' are processed by pthread_setname_np - // but we explicitly copy into a size-limited buffer to avoid any - // possible overflow. - char buf[32]; - snprintf(buf, sizeof(buf), "%s", name); - buf[sizeof(buf) - 1] = '\0'; - Solaris::_pthread_setname_np(pthread_self(), buf); - } -} - -bool os::bind_to_processor(uint processor_id) { - // We assume that a processorid_t can be stored in a uint. - assert(sizeof(uint) == sizeof(processorid_t), - "can't convert uint to processorid_t"); - int bind_result = - processor_bind(P_LWPID, // bind LWP. - P_MYID, // bind current LWP. - (processorid_t) processor_id, // id. - NULL); // don't return old binding. - return (bind_result == 0); -} - -// Return true if user is running as root. - -bool os::have_special_privileges() { - static bool init = false; - static bool privileges = false; - if (!init) { - privileges = (getuid() != geteuid()) || (getgid() != getegid()); - init = true; - } - return privileges; -} - - -void os::init_system_properties_values() { - // The next steps are taken in the product version: - // - // Obtain the JAVA_HOME value from the location of libjvm.so. - // This library should be located at: - // /jre/lib//{client|server}/libjvm.so. - // - // If "/jre/lib/" appears at the right place in the path, then we - // assume libjvm.so is installed in a JDK and we use this path. - // - // Otherwise exit with message: "Could not create the Java virtual machine." - // - // The following extra steps are taken in the debugging version: - // - // If "/jre/lib/" does NOT appear at the right place in the path - // instead of exit check for $JAVA_HOME environment variable. - // - // If it is defined and we are able to locate $JAVA_HOME/jre/lib/, - // then we append a fake suffix "hotspot/libjvm.so" to this path so - // it looks like libjvm.so is installed there - // /jre/lib//hotspot/libjvm.so. - // - // Otherwise exit. - // - // Important note: if the location of libjvm.so changes this - // code needs to be changed accordingly. - -// Base path of extensions installed on the system. -#define SYS_EXT_DIR "/usr/jdk/packages" -#define EXTENSIONS_DIR "/lib/ext" - - // Buffer that fits several sprintfs. - // Note that the space for the colon and the trailing null are provided - // by the nulls included by the sizeof operator. - const size_t bufsize = - MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. - sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path - (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir - char *buf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); - - // sysclasspath, java_home, dll_dir - { - char *pslash; - os::jvm_path(buf, bufsize); - - // Found the full path to libjvm.so. - // Now cut the path to /jre if we can. - *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; // Get rid of /{client|server|hotspot}. - } - Arguments::set_dll_dir(buf); - - if (pslash != NULL) { - pslash = strrchr(buf, '/'); - if (pslash != NULL) { - *pslash = '\0'; // Get rid of /lib. - } - } - Arguments::set_java_home(buf); - if (!set_boot_path('/', ':')) { - vm_exit_during_initialization("Failed setting boot class path.", NULL); - } - } - - // Where to look for native libraries. - { - // Use dlinfo() to determine the correct java.library.path. - // - // If we're launched by the Java launcher, and the user - // does not set java.library.path explicitly on the commandline, - // the Java launcher sets LD_LIBRARY_PATH for us and unsets - // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case - // dlinfo returns LD_LIBRARY_PATH + crle settings (including - // /usr/lib), which is exactly what we want. - // - // If the user does set java.library.path, it completely - // overwrites this setting, and always has. - // - // If we're not launched by the Java launcher, we may - // get here with any/all of the LD_LIBRARY_PATH[_32|64] - // settings. Again, dlinfo does exactly what we want. - - Dl_serinfo info_sz, *info = &info_sz; - Dl_serpath *path; - char *library_path; - char *common_path = buf; - - // Determine search path count and required buffer size. - if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { - FREE_C_HEAP_ARRAY(char, buf); - vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); - } - - // Allocate new buffer and initialize. - info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal); - info->dls_size = info_sz.dls_size; - info->dls_cnt = info_sz.dls_cnt; - - // Obtain search path information. - if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { - FREE_C_HEAP_ARRAY(char, buf); - FREE_C_HEAP_ARRAY(char, info); - vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); - } - - path = &info->dls_serpath[0]; - - // Note: Due to a legacy implementation, most of the library path - // is set in the launcher. This was to accomodate linking restrictions - // on legacy Solaris implementations (which are no longer supported). - // Eventually, all the library path setting will be done here. - // - // However, to prevent the proliferation of improperly built native - // libraries, the new path component /usr/jdk/packages is added here. - - // Construct the invariant part of ld_library_path. - sprintf(common_path, SYS_EXT_DIR "/lib"); - - // Struct size is more than sufficient for the path components obtained - // through the dlinfo() call, so only add additional space for the path - // components explicitly added here. - size_t library_path_size = info->dls_size + strlen(common_path); - library_path = NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal); - library_path[0] = '\0'; - - // Construct the desired Java library path from the linker's library - // search path. - // - // For compatibility, it is optimal that we insert the additional path - // components specific to the Java VM after those components specified - // in LD_LIBRARY_PATH (if any) but before those added by the ld.so - // infrastructure. - if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it. - strcpy(library_path, common_path); - } else { - int inserted = 0; - int i; - for (i = 0; i < info->dls_cnt; i++, path++) { - uint_t flags = path->dls_flags & LA_SER_MASK; - if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { - strcat(library_path, common_path); - strcat(library_path, os::path_separator()); - inserted = 1; - } - strcat(library_path, path->dls_name); - strcat(library_path, os::path_separator()); - } - // Eliminate trailing path separator. - library_path[strlen(library_path)-1] = '\0'; - } - - // happens before argument parsing - can't use a trace flag - // tty->print_raw("init_system_properties_values: native lib path: "); - // tty->print_raw_cr(library_path); - - // Callee copies into its own buffer. - Arguments::set_library_path(library_path); - - FREE_C_HEAP_ARRAY(char, library_path); - FREE_C_HEAP_ARRAY(char, info); - } - - // Extensions directories. - sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); - Arguments::set_ext_dirs(buf); - - FREE_C_HEAP_ARRAY(char, buf); - -#undef SYS_EXT_DIR -#undef EXTENSIONS_DIR -} - -void os::breakpoint() { - BREAKPOINT; -} - -extern "C" void breakpoint() { - // use debugger to set breakpoint here -} - -static thread_t main_thread; - -// Thread start routine for all newly created threads -extern "C" void* thread_native_entry(void* thread_addr) { - - Thread* thread = (Thread*)thread_addr; - - thread->record_stack_base_and_size(); - - // Try to randomize the cache line index of hot stack frames. - // This helps when threads of the same stack traces evict each other's - // cache lines. The threads can be either from the same JVM instance, or - // from different JVM instances. The benefit is especially true for - // processors with hyperthreading technology. - static int counter = 0; - int pid = os::current_process_id(); - alloca(((pid ^ counter++) & 7) * 128); - - int prio; - - thread->initialize_thread_current(); - - OSThread* osthr = thread->osthread(); - - osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound - - log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", - os::current_thread_id()); - - if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } - } - - // Our priority was set when we were created, and stored in the - // osthread, but couldn't be passed through to our LWP until now. - // So read back the priority and set it again. - - if (osthr->thread_id() != -1) { - if (UseThreadPriorities) { - int prio = osthr->native_priority(); - if (ThreadPriorityVerbose) { - tty->print_cr("Starting Thread " INTPTR_FORMAT ", LWP is " - INTPTR_FORMAT ", setting priority: %d\n", - osthr->thread_id(), osthr->lwp_id(), prio); - } - os::set_native_priority(thread, prio); - } - } else if (ThreadPriorityVerbose) { - warning("Can't set priority in _start routine, thread id hasn't been set\n"); - } - - assert(osthr->get_state() == RUNNABLE, "invalid os thread state"); - - // initialize signal mask for this thread - os::Solaris::hotspot_sigmask(thread); - - os::Solaris::init_thread_fpu_state(); - std::set_terminate(_handle_uncaught_cxx_exception); - - thread->call_run(); - - // Note: at this point the thread object may already have deleted itself. - // Do not dereference it from here on out. - - // One less thread is executing - // When the VMThread gets here, the main thread may have already exited - // which frees the CodeHeap containing the Atomic::dec code - if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) { - Atomic::dec(&os::Solaris::_os_thread_count); - } - - log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); - - if (UseDetachedThreads) { - thr_exit(NULL); - ShouldNotReachHere(); - } - return NULL; -} - -static OSThread* create_os_thread(Thread* thread, thread_t thread_id) { - // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); - if (osthread == NULL) return NULL; - - // Store info on the Solaris thread into the OSThread - osthread->set_thread_id(thread_id); - osthread->set_lwp_id(_lwp_self()); - - if (UseNUMA) { - int lgrp_id = os::numa_get_group_id(); - if (lgrp_id != -1) { - thread->set_lgrp_id(lgrp_id); - } - } - - if (ThreadPriorityVerbose) { - tty->print_cr("In create_os_thread, Thread " INTPTR_FORMAT ", LWP is " INTPTR_FORMAT "\n", - osthread->thread_id(), osthread->lwp_id()); - } - - // Initial thread state is INITIALIZED, not SUSPENDED - osthread->set_state(INITIALIZED); - - return osthread; -} - -void os::Solaris::hotspot_sigmask(Thread* thread) { - //Save caller's signal mask - sigset_t sigmask; - pthread_sigmask(SIG_SETMASK, NULL, &sigmask); - OSThread *osthread = thread->osthread(); - osthread->set_caller_sigmask(sigmask); - - pthread_sigmask(SIG_UNBLOCK, os::Solaris::unblocked_signals(), NULL); - if (!ReduceSignalUsage) { - if (thread->is_VM_thread()) { - // Only the VM thread handles BREAK_SIGNAL ... - pthread_sigmask(SIG_UNBLOCK, vm_signals(), NULL); - } else { - // ... all other threads block BREAK_SIGNAL - assert(!sigismember(vm_signals(), SIGINT), "SIGINT should not be blocked"); - pthread_sigmask(SIG_BLOCK, vm_signals(), NULL); - } - } -} - -bool os::create_attached_thread(JavaThread* thread) { -#ifdef ASSERT - thread->verify_not_published(); -#endif - OSThread* osthread = create_os_thread(thread, thr_self()); - if (osthread == NULL) { - return false; - } - - // Initial thread state is RUNNABLE - osthread->set_state(RUNNABLE); - thread->set_osthread(osthread); - - // initialize signal mask for this thread - // and save the caller's signal mask - os::Solaris::hotspot_sigmask(thread); - - log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", - os::current_thread_id()); - - return true; -} - -bool os::create_main_thread(JavaThread* thread) { -#ifdef ASSERT - thread->verify_not_published(); -#endif - if (_starting_thread == NULL) { - _starting_thread = create_os_thread(thread, main_thread); - if (_starting_thread == NULL) { - return false; - } - } - - // The primodial thread is runnable from the start - _starting_thread->set_state(RUNNABLE); - - thread->set_osthread(_starting_thread); - - // initialize signal mask for this thread - // and save the caller's signal mask - os::Solaris::hotspot_sigmask(thread); - - return true; -} - -// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() -static char* describe_thr_create_attributes(char* buf, size_t buflen, - size_t stacksize, long flags) { - stringStream ss(buf, buflen); - ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); - ss.print("flags: "); - #define PRINT_FLAG(f) if (flags & f) ss.print( #f " "); - #define ALL(X) \ - X(THR_SUSPENDED) \ - X(THR_DETACHED) \ - X(THR_BOUND) \ - X(THR_NEW_LWP) \ - X(THR_DAEMON) - ALL(PRINT_FLAG) - #undef ALL - #undef PRINT_FLAG - return buf; -} - -// return default stack size for thr_type -size_t os::Posix::default_stack_size(os::ThreadType thr_type) { - // default stack size when not specified by caller is 1M (2M for LP64) - size_t s = (BytesPerWord >> 2) * K * K; - return s; -} - -bool os::create_thread(Thread* thread, ThreadType thr_type, - size_t req_stack_size) { - // Allocate the OSThread object - OSThread* osthread = new OSThread(NULL, NULL); - if (osthread == NULL) { - return false; - } - - if (ThreadPriorityVerbose) { - char *thrtyp; - switch (thr_type) { - case vm_thread: - thrtyp = (char *)"vm"; - break; - case cgc_thread: - thrtyp = (char *)"cgc"; - break; - case pgc_thread: - thrtyp = (char *)"pgc"; - break; - case java_thread: - thrtyp = (char *)"java"; - break; - case compiler_thread: - thrtyp = (char *)"compiler"; - break; - case watcher_thread: - thrtyp = (char *)"watcher"; - break; - default: - thrtyp = (char *)"unknown"; - break; - } - tty->print_cr("In create_thread, creating a %s thread\n", thrtyp); - } - - // calculate stack size if it's not specified by caller - size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size); - - // Initial state is ALLOCATED but not INITIALIZED - osthread->set_state(ALLOCATED); - - if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) { - // We got lots of threads. Check if we still have some address space left. - // Need to be at least 5Mb of unreserved address space. We do check by - // trying to reserve some. - const size_t VirtualMemoryBangSize = 20*K*K; - char* mem = os::reserve_memory(VirtualMemoryBangSize); - if (mem == NULL) { - delete osthread; - return false; - } else { - // Release the memory again - os::release_memory(mem, VirtualMemoryBangSize); - } - } - - // Setup osthread because the child thread may need it. - thread->set_osthread(osthread); - - // Create the Solaris thread - thread_t tid = 0; - long flags = (UseDetachedThreads ? THR_DETACHED : 0) | THR_SUSPENDED; - int status; - - // Mark that we don't have an lwp or thread id yet. - // In case we attempt to set the priority before the thread starts. - osthread->set_lwp_id(-1); - osthread->set_thread_id(-1); - - status = thr_create(NULL, stack_size, thread_native_entry, thread, flags, &tid); - - char buf[64]; - if (status == 0) { - log_info(os, thread)("Thread started (tid: " UINTX_FORMAT ", attributes: %s). ", - (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); - } else { - log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", - os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); - // Log some OS information which might explain why creating the thread failed. - log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); - LogStream st(Log(os, thread)::info()); - os::Posix::print_rlimit_info(&st); - os::print_memory_info(&st); - } - - if (status != 0) { - thread->set_osthread(NULL); - // Need to clean up stuff we've allocated so far - delete osthread; - return false; - } - - Atomic::inc(&os::Solaris::_os_thread_count); - - // Store info on the Solaris thread into the OSThread - osthread->set_thread_id(tid); - - // Remember that we created this thread so we can set priority on it - osthread->set_vm_created(); - - // Most thread types will set an explicit priority before starting the thread, - // but for those that don't we need a valid value to read back in thread_native_entry. - osthread->set_native_priority(NormPriority); - - // Initial thread state is INITIALIZED, not SUSPENDED - osthread->set_state(INITIALIZED); - - // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain - return true; -} - -debug_only(static bool signal_sets_initialized = false); -static sigset_t unblocked_sigs, vm_sigs; - -void os::Solaris::signal_sets_init() { - // Should also have an assertion stating we are still single-threaded. - assert(!signal_sets_initialized, "Already initialized"); - // Fill in signals that are necessarily unblocked for all threads in - // the VM. Currently, we unblock the following signals: - // SHUTDOWN{1,2,3}_SIGNAL: for shutdown hooks support (unless over-ridden - // by -Xrs (=ReduceSignalUsage)); - // BREAK_SIGNAL which is unblocked only by the VM thread and blocked by all - // other threads. The "ReduceSignalUsage" boolean tells us not to alter - // the dispositions or masks wrt these signals. - // Programs embedding the VM that want to use the above signals for their - // own purposes must, at this time, use the "-Xrs" option to prevent - // interference with shutdown hooks and BREAK_SIGNAL thread dumping. - // (See bug 4345157, and other related bugs). - // In reality, though, unblocking these signals is really a nop, since - // these signals are not blocked by default. - sigemptyset(&unblocked_sigs); - sigaddset(&unblocked_sigs, SIGILL); - sigaddset(&unblocked_sigs, SIGSEGV); - sigaddset(&unblocked_sigs, SIGBUS); - sigaddset(&unblocked_sigs, SIGFPE); - sigaddset(&unblocked_sigs, ASYNC_SIGNAL); - - if (!ReduceSignalUsage) { - if (!os::Posix::is_sig_ignored(SHUTDOWN1_SIGNAL)) { - sigaddset(&unblocked_sigs, SHUTDOWN1_SIGNAL); - } - if (!os::Posix::is_sig_ignored(SHUTDOWN2_SIGNAL)) { - sigaddset(&unblocked_sigs, SHUTDOWN2_SIGNAL); - } - if (!os::Posix::is_sig_ignored(SHUTDOWN3_SIGNAL)) { - sigaddset(&unblocked_sigs, SHUTDOWN3_SIGNAL); - } - } - // Fill in signals that are blocked by all but the VM thread. - sigemptyset(&vm_sigs); - if (!ReduceSignalUsage) { - sigaddset(&vm_sigs, BREAK_SIGNAL); - } - debug_only(signal_sets_initialized = true); - - // For diagnostics only used in run_periodic_checks - sigemptyset(&check_signal_done); -} - -// These are signals that are unblocked while a thread is running Java. -// (For some reason, they get blocked by default.) -sigset_t* os::Solaris::unblocked_signals() { - assert(signal_sets_initialized, "Not initialized"); - return &unblocked_sigs; -} - -// These are the signals that are blocked while a (non-VM) thread is -// running Java. Only the VM thread handles these signals. -sigset_t* os::Solaris::vm_signals() { - assert(signal_sets_initialized, "Not initialized"); - return &vm_sigs; -} - -// CR 7190089: on Solaris, primordial thread's stack needs adjusting. -// Without the adjustment, stack size is incorrect if stack is set to unlimited (ulimit -s unlimited). -void os::Solaris::correct_stack_boundaries_for_primordial_thread(Thread* thr) { - assert(is_primordial_thread(), "Call only for primordial thread"); - - JavaThread* jt = (JavaThread *)thr; - assert(jt != NULL, "Sanity check"); - size_t stack_size; - address base = jt->stack_base(); - if (Arguments::created_by_java_launcher()) { - // Use 2MB to allow for Solaris 7 64 bit mode. - stack_size = JavaThread::stack_size_at_create() == 0 - ? 2048*K : JavaThread::stack_size_at_create(); - - // There are rare cases when we may have already used more than - // the basic stack size allotment before this method is invoked. - // Attempt to allow for a normally sized java_stack. - size_t current_stack_offset = (size_t)(base - (address)&stack_size); - stack_size += ReservedSpace::page_align_size_down(current_stack_offset); - } else { - // 6269555: If we were not created by a Java launcher, i.e. if we are - // running embedded in a native application, treat the primordial thread - // as much like a native attached thread as possible. This means using - // the current stack size from thr_stksegment(), unless it is too large - // to reliably setup guard pages. A reasonable max size is 8MB. - size_t current_size = os::current_stack_size(); - // This should never happen, but just in case.... - if (current_size == 0) current_size = 2 * K * K; - stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size; - } - address bottom = align_up(base - stack_size, os::vm_page_size());; - stack_size = (size_t)(base - bottom); - - assert(stack_size > 0, "Stack size calculation problem"); - - if (stack_size > jt->stack_size()) { -#ifndef PRODUCT - struct rlimit limits; - getrlimit(RLIMIT_STACK, &limits); - size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur); - assert(size >= jt->stack_size(), "Stack size problem in main thread"); -#endif - tty->print_cr("Stack size of %d Kb exceeds current limit of %d Kb.\n" - "(Stack sizes are rounded up to a multiple of the system page size.)\n" - "See limit(1) to increase the stack size limit.", - stack_size / K, jt->stack_size() / K); - vm_exit(1); - } - assert(jt->stack_size() >= stack_size, - "Attempt to map more stack than was allocated"); - jt->set_stack_size(stack_size); - -} - - - -// Free Solaris resources related to the OSThread -void os::free_thread(OSThread* osthread) { - assert(osthread != NULL, "os::free_thread but osthread not set"); - - // We are told to free resources of the argument thread, - // but we can only really operate on the current thread. - assert(Thread::current()->osthread() == osthread, - "os::free_thread but not current thread"); - - // Restore caller's signal mask - sigset_t sigmask = osthread->caller_sigmask(); - pthread_sigmask(SIG_SETMASK, &sigmask, NULL); - - delete osthread; -} - -void os::pd_start_thread(Thread* thread) { - int status = thr_continue(thread->osthread()->thread_id()); - assert_status(status == 0, status, "thr_continue failed"); -} - - -intx os::current_thread_id() { - return (intx)thr_self(); -} - -static pid_t _initial_pid = 0; - -int os::current_process_id() { - return (int)(_initial_pid ? _initial_pid : getpid()); -} - -// gethrtime() should be monotonic according to the documentation, -// but some virtualized platforms are known to break this guarantee. -// getTimeNanos() must be guaranteed not to move backwards, so we -// are forced to add a check here. -inline hrtime_t getTimeNanos() { - const hrtime_t now = gethrtime(); - const hrtime_t prev = max_hrtime; - if (now <= prev) { - return prev; // same or retrograde time; - } - const hrtime_t obsv = Atomic::cmpxchg(&max_hrtime, prev, now); - assert(obsv >= prev, "invariant"); // Monotonicity - // If the CAS succeeded then we're done and return "now". - // If the CAS failed and the observed value "obsv" is >= now then - // we should return "obsv". If the CAS failed and now > obsv > prv then - // some other thread raced this thread and installed a new value, in which case - // we could either (a) retry the entire operation, (b) retry trying to install now - // or (c) just return obsv. We use (c). No loop is required although in some cases - // we might discard a higher "now" value in deference to a slightly lower but freshly - // installed obsv value. That's entirely benign -- it admits no new orderings compared - // to (a) or (b) -- and greatly reduces coherence traffic. - // We might also condition (c) on the magnitude of the delta between obsv and now. - // Avoiding excessive CAS operations to hot RW locations is critical. - // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate - return (prev == obsv) ? now : obsv; -} - -// Time since start-up in seconds to a fine granularity. -// Used by VMSelfDestructTimer and the MemProfiler. -double os::elapsedTime() { - return (double)(getTimeNanos() - first_hrtime) / (double)hrtime_hz; -} - -jlong os::elapsed_counter() { - return (jlong)(getTimeNanos() - first_hrtime); -} - -jlong os::elapsed_frequency() { - return hrtime_hz; -} - -// Return the real, user, and system times in seconds from an -// arbitrary fixed point in the past. -bool os::getTimesSecs(double* process_real_time, - double* process_user_time, - double* process_system_time) { - struct tms ticks; - clock_t real_ticks = times(&ticks); - - if (real_ticks == (clock_t) (-1)) { - return false; - } else { - double ticks_per_second = (double) clock_tics_per_sec; - *process_user_time = ((double) ticks.tms_utime) / ticks_per_second; - *process_system_time = ((double) ticks.tms_stime) / ticks_per_second; - // For consistency return the real time from getTimeNanos() - // converted to seconds. - *process_real_time = ((double) getTimeNanos()) / ((double) NANOUNITS); - - return true; - } -} - -bool os::supports_vtime() { return true; } - -double os::elapsedVTime() { - return (double)gethrvtime() / (double)hrtime_hz; -} - -// Must return millis since Jan 1 1970 for JVM_CurrentTimeMillis -jlong os::javaTimeMillis() { - timeval t; - if (gettimeofday(&t, NULL) == -1) { - fatal("os::javaTimeMillis: gettimeofday (%s)", os::strerror(errno)); - } - return jlong(t.tv_sec) * 1000 + jlong(t.tv_usec) / 1000; -} - -// Must return seconds+nanos since Jan 1 1970. This must use the same -// time source as javaTimeMillis and can't use get_nsec_fromepoch as -// we need better than 1ms accuracy -void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) { - timeval t; - if (gettimeofday(&t, NULL) == -1) { - fatal("os::javaTimeSystemUTC: gettimeofday (%s)", os::strerror(errno)); - } - seconds = jlong(t.tv_sec); - nanos = jlong(t.tv_usec) * 1000; -} - - -jlong os::javaTimeNanos() { - return (jlong)getTimeNanos(); -} - -void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // gethrtime() uses all 64 bits - info_ptr->may_skip_backward = false; // not subject to resetting or drifting - info_ptr->may_skip_forward = false; // not subject to resetting or drifting - info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time -} - -char * os::local_time_string(char *buf, size_t buflen) { - struct tm t; - time_t long_time; - time(&long_time); - localtime_r(&long_time, &t); - jio_snprintf(buf, buflen, "%d-%02d-%02d %02d:%02d:%02d", - t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, - t.tm_hour, t.tm_min, t.tm_sec); - return buf; -} - -// Note: os::shutdown() might be called very early during initialization, or -// called from signal handler. Before adding something to os::shutdown(), make -// sure it is async-safe and can handle partially initialized VM. -void os::shutdown() { - - // allow PerfMemory to attempt cleanup of any persistent resources - perfMemory_exit(); - - // needs to remove object in file system - AttachListener::abort(); - - // flush buffered output, finish log files - ostream_abort(); - - // Check for abort hook - abort_hook_t abort_hook = Arguments::abort_hook(); - if (abort_hook != NULL) { - abort_hook(); - } -} - -// Note: os::abort() might be called very early during initialization, or -// called from signal handler. Before adding something to os::abort(), make -// sure it is async-safe and can handle partially initialized VM. -void os::abort(bool dump_core, void* siginfo, const void* context) { - os::shutdown(); - if (dump_core) { - ::abort(); // dump core (for debugging) - } - - ::exit(1); -} - -// Die immediately, no exit hook, no abort hook, no cleanup. -// Dump a core file, if possible, for debugging. -void os::die() { - if (TestUnresponsiveErrorHandler && !CreateCoredumpOnCrash) { - // For TimeoutInErrorHandlingTest.java, we just kill the VM - // and don't take the time to generate a core file. - os::signal_raise(SIGKILL); - } else { - ::abort(); - } -} - -// DLL functions - -const char* os::dll_file_extension() { return ".so"; } - -// This must be hard coded because it's the system's temporary -// directory not the java application's temp directory, ala java.io.tmpdir. -const char* os::get_temp_directory() { return "/tmp"; } - -// check if addr is inside libjvm.so -bool os::address_is_in_vm(address addr) { - static address libjvm_base_addr; - Dl_info dlinfo; - - if (libjvm_base_addr == NULL) { - if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) { - libjvm_base_addr = (address)dlinfo.dli_fbase; - } - assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm"); - } - - if (dladdr((void *)addr, &dlinfo) != 0) { - if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true; - } - - return false; -} - -typedef int (*dladdr1_func_type)(void *, Dl_info *, void **, int); -static dladdr1_func_type dladdr1_func = NULL; - -bool os::dll_address_to_function_name(address addr, char *buf, - int buflen, int * offset, - bool demangle) { - // buf is not optional, but offset is optional - assert(buf != NULL, "sanity check"); - - Dl_info dlinfo; - - // dladdr1_func was initialized in os::init() - if (dladdr1_func != NULL) { - // yes, we have dladdr1 - - // Support for dladdr1 is checked at runtime; it may be - // available even if the vm is built on a machine that does - // not have dladdr1 support. Make sure there is a value for - // RTLD_DL_SYMENT. -#ifndef RTLD_DL_SYMENT - #define RTLD_DL_SYMENT 1 -#endif -#ifdef _LP64 - Elf64_Sym * info; -#else - Elf32_Sym * info; -#endif - if (dladdr1_func((void *)addr, &dlinfo, (void **)&info, - RTLD_DL_SYMENT) != 0) { - // see if we have a matching symbol that covers our address - if (dlinfo.dli_saddr != NULL && - (char *)dlinfo.dli_saddr + info->st_size > (char *)addr) { - if (dlinfo.dli_sname != NULL) { - if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) { - jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); - } - if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; - return true; - } - } - // no matching symbol so try for just file info - if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) { - if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), - buf, buflen, offset, dlinfo.dli_fname, demangle)) { - return true; - } - } - } - buf[0] = '\0'; - if (offset != NULL) *offset = -1; - return false; - } - - // no, only dladdr is available - if (dladdr((void *)addr, &dlinfo) != 0) { - // see if we have a matching symbol - if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) { - if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) { - jio_snprintf(buf, buflen, dlinfo.dli_sname); - } - if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; - return true; - } - // no matching symbol so try for just file info - if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) { - if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), - buf, buflen, offset, dlinfo.dli_fname, demangle)) { - return true; - } - } - } - buf[0] = '\0'; - if (offset != NULL) *offset = -1; - return false; -} - -bool os::dll_address_to_library_name(address addr, char* buf, - int buflen, int* offset) { - // buf is not optional, but offset is optional - assert(buf != NULL, "sanity check"); - - Dl_info dlinfo; - - if (dladdr((void*)addr, &dlinfo) != 0) { - if (dlinfo.dli_fname != NULL) { - jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname); - } - if (dlinfo.dli_fbase != NULL && offset != NULL) { - *offset = addr - (address)dlinfo.dli_fbase; - } - return true; - } - - buf[0] = '\0'; - if (offset) *offset = -1; - return false; -} - -int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { - Dl_info dli; - // Sanity check? - if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 || - dli.dli_fname == NULL) { - return 1; - } - - void * handle = dlopen(dli.dli_fname, RTLD_LAZY); - if (handle == NULL) { - return 1; - } - - Link_map *map; - dlinfo(handle, RTLD_DI_LINKMAP, &map); - if (map == NULL) { - dlclose(handle); - return 1; - } - - while (map->l_prev != NULL) { - map = map->l_prev; - } - - while (map != NULL) { - // Iterate through all map entries and call callback with fields of interest - if(callback(map->l_name, (address)map->l_addr, (address)0, param)) { - dlclose(handle); - return 1; - } - map = map->l_next; - } - - dlclose(handle); - return 0; -} - -int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { - outputStream * out = (outputStream *) param; - out->print_cr(PTR_FORMAT " \t%s", base_address, name); - return 0; -} - -void os::print_dll_info(outputStream * st) { - st->print_cr("Dynamic libraries:"); st->flush(); - if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) { - st->print_cr("Error: Cannot print dynamic libraries."); - } -} - -static void change_endianness(Elf32_Half& val) { - unsigned char *ptr = (unsigned char *)&val; - unsigned char swp = ptr[0]; - ptr[0] = ptr[1]; - ptr[1] = swp; -} - -// Loads .dll/.so and -// in case of error it checks if .dll/.so was built for the -// same architecture as Hotspot is running on - -void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { - log_info(os)("attempting shared library load of %s", filename); - - void * result= ::dlopen(filename, RTLD_LAZY); - if (result != NULL) { - // Successful loading - Events::log(NULL, "Loaded shared library %s", filename); - log_info(os)("shared library load of %s was successful", filename); - return result; - } - - Elf32_Ehdr elf_head; - const char* error_report = ::dlerror(); - if (error_report == NULL) { - error_report = "dlerror returned no error description"; - } - if (ebuf != NULL && ebuflen > 0) { - ::strncpy(ebuf, error_report, ebuflen-1); - ebuf[ebuflen-1]='\0'; - } - - Events::log(NULL, "Loading shared library %s failed, %s", filename, error_report); - log_info(os)("shared library load of %s failed, %s", filename, error_report); - - int diag_msg_max_length=ebuflen-strlen(ebuf); - char* diag_msg_buf=ebuf+strlen(ebuf); - - if (diag_msg_max_length==0) { - // No more space in ebuf for additional diagnostics message - return NULL; - } - - - int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK); - - if (file_descriptor < 0) { - // Can't open library, report dlerror() message - return NULL; - } - - bool failed_to_read_elf_head= - (sizeof(elf_head)!= - (::read(file_descriptor, &elf_head,sizeof(elf_head)))); - - ::close(file_descriptor); - if (failed_to_read_elf_head) { - // file i/o error - report dlerror() msg - return NULL; - } - - if (elf_head.e_ident[EI_DATA] != LITTLE_ENDIAN_ONLY(ELFDATA2LSB) BIG_ENDIAN_ONLY(ELFDATA2MSB)) { - // handle invalid/out of range endianness values - if (elf_head.e_ident[EI_DATA] == 0 || elf_head.e_ident[EI_DATA] > 2) { - return NULL; - } - change_endianness(elf_head.e_machine); - } - - typedef struct { - Elf32_Half code; // Actual value as defined in elf.h - Elf32_Half compat_class; // Compatibility of archs at VM's sense - unsigned char elf_class; // 32 or 64 bit - unsigned char endianess; // MSB or LSB - char* name; // String representation - } arch_t; - - static const arch_t arch_array[]={ - {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, - {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, - {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"}, - {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"}, - {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, - {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, - {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, - {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, - {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, - {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, - // we only support 64 bit z architecture - {EM_S390, EM_S390, ELFCLASS64, ELFDATA2MSB, (char*)"IBM System/390"}, - {EM_AARCH64, EM_AARCH64, ELFCLASS64, ELFDATA2LSB, (char*)"AARCH64"} - }; - -#if (defined IA32) - static Elf32_Half running_arch_code=EM_386; -#elif (defined AMD64) - static Elf32_Half running_arch_code=EM_X86_64; -#elif (defined IA64) - static Elf32_Half running_arch_code=EM_IA_64; -#elif (defined __sparc) && (defined _LP64) - static Elf32_Half running_arch_code=EM_SPARCV9; -#elif (defined __sparc) && (!defined _LP64) - static Elf32_Half running_arch_code=EM_SPARC; -#elif (defined __powerpc64__) - static Elf32_Half running_arch_code=EM_PPC64; -#elif (defined __powerpc__) - static Elf32_Half running_arch_code=EM_PPC; -#elif (defined ARM) - static Elf32_Half running_arch_code=EM_ARM; -#else - #error Method os::dll_load requires that one of following is defined:\ - IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM -#endif - - // Identify compatibility class for VM's architecture and library's architecture - // Obtain string descriptions for architectures - - arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL}; - int running_arch_index=-1; - - for (unsigned int i=0; i < ARRAY_SIZE(arch_array); i++) { - if (running_arch_code == arch_array[i].code) { - running_arch_index = i; - } - if (lib_arch.code == arch_array[i].code) { - lib_arch.compat_class = arch_array[i].compat_class; - lib_arch.name = arch_array[i].name; - } - } - - assert(running_arch_index != -1, - "Didn't find running architecture code (running_arch_code) in arch_array"); - if (running_arch_index == -1) { - // Even though running architecture detection failed - // we may still continue with reporting dlerror() message - return NULL; - } - - if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { - if (lib_arch.name != NULL) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load %s .so on a %s platform)", - lib_arch.name, arch_array[running_arch_index].name); - } else { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", - lib_arch.code, arch_array[running_arch_index].name); - } - return NULL; - } - - if (lib_arch.endianess != arch_array[running_arch_index].endianess) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); - return NULL; - } - - // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit - if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); - return NULL; - } - - if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { - ::snprintf(diag_msg_buf, diag_msg_max_length-1, - " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", - (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); - return NULL; - } - - return NULL; -} - -void* os::dll_lookup(void* handle, const char* name) { - return dlsym(handle, name); -} - -void* os::get_default_process_handle() { - return (void*)::dlopen(NULL, RTLD_LAZY); -} - -static inline time_t get_mtime(const char* filename) { - struct stat st; - int ret = os::stat(filename, &st); - assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno)); - return st.st_mtime; -} - -int os::compare_file_modified_times(const char* file1, const char* file2) { - time_t t1 = get_mtime(file1); - time_t t2 = get_mtime(file2); - return t1 - t2; -} - -static bool _print_ascii_file(const char* filename, outputStream* st) { - int fd = ::open(filename, O_RDONLY); - if (fd == -1) { - return false; - } - - char buf[32]; - int bytes; - while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) { - st->print_raw(buf, bytes); - } - - ::close(fd); - - return true; -} - -void os::print_os_info_brief(outputStream* st) { - os::Solaris::print_distro_info(st); - - os::Posix::print_uname_info(st); - - os::Solaris::print_libversion_info(st); -} - -void os::print_os_info(outputStream* st) { - st->print("OS:"); - - os::Solaris::print_distro_info(st); - - os::Posix::print_uname_info(st); - - os::Posix::print_uptime_info(st); - - os::Solaris::print_libversion_info(st); - - os::Posix::print_rlimit_info(st); - - os::Posix::print_load_average(st); -} - -void os::Solaris::print_distro_info(outputStream* st) { - if (!_print_ascii_file("/etc/release", st)) { - st->print("Solaris"); - } - st->cr(); -} - -void os::get_summary_os_info(char* buf, size_t buflen) { - strncpy(buf, "Solaris", buflen); // default to plain solaris - FILE* fp = fopen("/etc/release", "r"); - if (fp != NULL) { - char tmp[256]; - // Only get the first line and chop out everything but the os name. - if (fgets(tmp, sizeof(tmp), fp)) { - char* ptr = tmp; - // skip past whitespace characters - while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++; - if (*ptr != '\0') { - char* nl = strchr(ptr, '\n'); - if (nl != NULL) *nl = '\0'; - strncpy(buf, ptr, buflen); - } - } - fclose(fp); - } -} - -void os::Solaris::print_libversion_info(outputStream* st) { - st->print(" (T2 libthread)"); - st->cr(); -} - -static bool check_addr0(outputStream* st) { - jboolean status = false; - const int read_chunk = 200; - int ret = 0; - int nmap = 0; - int fd = ::open("/proc/self/map",O_RDONLY); - if (fd >= 0) { - prmap_t *p = NULL; - char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t)); - if (NULL == mbuff) { - ::close(fd); - return status; - } - while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) { - //check if read() has not read partial data - if( 0 != ret % sizeof(prmap_t)){ - break; - } - nmap = ret / sizeof(prmap_t); - p = (prmap_t *)mbuff; - for(int i = 0; i < nmap; i++){ - if (p->pr_vaddr == 0x0) { - st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024); - st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname); - st->print("Access: "); - st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-"); - st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-"); - st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-"); - st->cr(); - status = true; - } - p++; - } - } - free(mbuff); - ::close(fd); - } - return status; -} - -void os::get_summary_cpu_info(char* buf, size_t buflen) { - // Get MHz with system call. We don't seem to already have this. - processor_info_t stats; - processorid_t id = getcpuid(); - int clock = 0; - if (processor_info(id, &stats) != -1) { - clock = stats.pi_clock; // pi_processor_type isn't more informative than below - } -#ifdef AMD64 - snprintf(buf, buflen, "x86 64 bit %d MHz", clock); -#else - // must be sparc - snprintf(buf, buflen, "Sparcv9 64 bit %d MHz", clock); -#endif -} - -void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { - // Nothing to do for now. -} - -void os::print_memory_info(outputStream* st) { - st->print("Memory:"); - st->print(" %dk page", os::vm_page_size()>>10); - st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10); - st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); - st->cr(); - (void) check_addr0(st); -} - -// Moved from whole group, because we need them here for diagnostic -// prints. -static int Maxsignum = 0; -static int *ourSigFlags = NULL; - -int os::Solaris::get_our_sigflags(int sig) { - assert(ourSigFlags!=NULL, "signal data structure not initialized"); - assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range"); - return ourSigFlags[sig]; -} - -void os::Solaris::set_our_sigflags(int sig, int flags) { - assert(ourSigFlags!=NULL, "signal data structure not initialized"); - assert(sig > 0 && sig < Maxsignum, "vm signal out of expected range"); - ourSigFlags[sig] = flags; -} - - -static const char* get_signal_handler_name(address handler, - char* buf, int buflen) { - int offset; - bool found = os::dll_address_to_library_name(handler, buf, buflen, &offset); - if (found) { - // skip directory names - const char *p1, *p2; - p1 = buf; - size_t len = strlen(os::file_separator()); - while ((p2 = strstr(p1, os::file_separator())) != NULL) p1 = p2 + len; - jio_snprintf(buf, buflen, "%s+0x%x", p1, offset); - } else { - jio_snprintf(buf, buflen, PTR_FORMAT, handler); - } - return buf; -} - -static void print_signal_handler(outputStream* st, int sig, - char* buf, size_t buflen) { - struct sigaction sa; - - sigaction(sig, NULL, &sa); - - st->print("%s: ", os::exception_name(sig, buf, buflen)); - - address handler = (sa.sa_flags & SA_SIGINFO) - ? CAST_FROM_FN_PTR(address, sa.sa_sigaction) - : CAST_FROM_FN_PTR(address, sa.sa_handler); - - if (handler == CAST_FROM_FN_PTR(address, SIG_DFL)) { - st->print("SIG_DFL"); - } else if (handler == CAST_FROM_FN_PTR(address, SIG_IGN)) { - st->print("SIG_IGN"); - } else { - st->print("[%s]", get_signal_handler_name(handler, buf, buflen)); - } - - st->print(", sa_mask[0]="); - os::Posix::print_signal_set_short(st, &sa.sa_mask); - - address rh = VMError::get_resetted_sighandler(sig); - // May be, handler was resetted by VMError? - if (rh != NULL) { - handler = rh; - sa.sa_flags = VMError::get_resetted_sigflags(sig); - } - - st->print(", sa_flags="); - os::Posix::print_sa_flags(st, sa.sa_flags); - - // Check: is it our handler? - if (handler == CAST_FROM_FN_PTR(address, signalHandler)) { - // It is our signal handler - // check for flags - if (sa.sa_flags != os::Solaris::get_our_sigflags(sig)) { - st->print( - ", flags was changed from " PTR32_FORMAT ", consider using jsig library", - os::Solaris::get_our_sigflags(sig)); - } - } - st->cr(); -} - -void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) { - st->print_cr("Signal Handlers:"); - print_signal_handler(st, SIGSEGV, buf, buflen); - print_signal_handler(st, SIGBUS , buf, buflen); - print_signal_handler(st, SIGFPE , buf, buflen); - print_signal_handler(st, SIGPIPE, buf, buflen); - print_signal_handler(st, SIGXFSZ, buf, buflen); - print_signal_handler(st, SIGILL , buf, buflen); - print_signal_handler(st, ASYNC_SIGNAL, buf, buflen); - print_signal_handler(st, BREAK_SIGNAL, buf, buflen); - print_signal_handler(st, SHUTDOWN1_SIGNAL , buf, buflen); - print_signal_handler(st, SHUTDOWN2_SIGNAL , buf, buflen); - print_signal_handler(st, SHUTDOWN3_SIGNAL, buf, buflen); -} - -static char saved_jvm_path[MAXPATHLEN] = { 0 }; - -// Find the full path to the current module, libjvm.so -void os::jvm_path(char *buf, jint buflen) { - // Error checking. - if (buflen < MAXPATHLEN) { - assert(false, "must use a large-enough buffer"); - buf[0] = '\0'; - return; - } - // Lazy resolve the path to current module. - if (saved_jvm_path[0] != 0) { - strcpy(buf, saved_jvm_path); - return; - } - - Dl_info dlinfo; - int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo); - assert(ret != 0, "cannot locate libjvm"); - if (ret != 0 && dlinfo.dli_fname != NULL) { - if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { - return; - } - } else { - buf[0] = '\0'; - return; - } - - if (Arguments::sun_java_launcher_is_altjvm()) { - // Support for the java launcher's '-XXaltjvm=' option. Typical - // value for buf is "/jre/lib///libjvm.so". - // If "/jre/lib/" appears at the right place in the string, then - // assume we are installed in a JDK and we're done. Otherwise, check - // for a JAVA_HOME environment variable and fix up the path so it - // looks like libjvm.so is installed there (append a fake suffix - // hotspot/libjvm.so). - const char *p = buf + strlen(buf) - 1; - for (int count = 0; p > buf && count < 5; ++count) { - for (--p; p > buf && *p != '/'; --p) - /* empty */ ; - } - - if (strncmp(p, "/jre/lib/", 9) != 0) { - // Look for JAVA_HOME in the environment. - char* java_home_var = ::getenv("JAVA_HOME"); - if (java_home_var != NULL && java_home_var[0] != 0) { - char* jrelib_p; - int len; - - // Check the current module name "libjvm.so". - p = strrchr(buf, '/'); - assert(strstr(p, "/libjvm") == p, "invalid library name"); - - if (os::Posix::realpath(java_home_var, buf, buflen) == NULL) { - return; - } - // determine if this is a legacy image or modules image - // modules image doesn't have "jre" subdirectory - len = strlen(buf); - assert(len < buflen, "Ran out of buffer space"); - jrelib_p = buf + len; - snprintf(jrelib_p, buflen-len, "/jre/lib"); - if (0 != access(buf, F_OK)) { - snprintf(jrelib_p, buflen-len, "/lib"); - } - - if (0 == access(buf, F_OK)) { - // Use current module name "libjvm.so" - len = strlen(buf); - snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); - } else { - // Go back to path of .so - if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { - return; - } - } - } - } - } - - strncpy(saved_jvm_path, buf, MAXPATHLEN); - saved_jvm_path[MAXPATHLEN - 1] = '\0'; -} - - -void os::print_jni_name_prefix_on(outputStream* st, int args_size) { - // no prefix required, not even "_" -} - - -void os::print_jni_name_suffix_on(outputStream* st, int args_size) { - // no suffix required -} - -// sun.misc.Signal - -extern "C" { - static void UserHandler(int sig, void *siginfo, void *context) { - // Ctrl-C is pressed during error reporting, likely because the error - // handler fails to abort. Let VM die immediately. - if (sig == SIGINT && VMError::is_error_reported()) { - os::die(); - } - - os::signal_notify(sig); - // We do not need to reinstate the signal handler each time... - } -} - -void* os::user_handler() { - return CAST_FROM_FN_PTR(void*, UserHandler); -} - -extern "C" { - typedef void (*sa_handler_t)(int); - typedef void (*sa_sigaction_t)(int, siginfo_t *, void *); -} - -void* os::signal(int signal_number, void* handler) { - struct sigaction sigAct, oldSigAct; - sigfillset(&(sigAct.sa_mask)); - sigAct.sa_flags = SA_RESTART & ~SA_RESETHAND; - sigAct.sa_flags |= SA_SIGINFO; - sigAct.sa_handler = CAST_TO_FN_PTR(sa_handler_t, handler); - - if (sigaction(signal_number, &sigAct, &oldSigAct)) { - // -1 means registration failed - return (void *)-1; - } - - return CAST_FROM_FN_PTR(void*, oldSigAct.sa_handler); -} - -void os::signal_raise(int signal_number) { - raise(signal_number); -} - -// The following code is moved from os.cpp for making this -// code platform specific, which it is by its very nature. - -// a counter for each possible signal value -static int Sigexit = 0; -static jint *pending_signals = NULL; -static int *preinstalled_sigs = NULL; -static struct sigaction *chainedsigactions = NULL; -static Semaphore* sig_sem = NULL; - -int os::sigexitnum_pd() { - assert(Sigexit > 0, "signal memory not yet initialized"); - return Sigexit; -} - -void os::Solaris::init_signal_mem() { - // Initialize signal structures - Maxsignum = SIGRTMAX; - Sigexit = Maxsignum+1; - assert(Maxsignum >0, "Unable to obtain max signal number"); - - // Initialize signal structures - // pending_signals has one int per signal - // The additional signal is for SIGEXIT - exit signal to signal_thread - pending_signals = (jint *)os::malloc(sizeof(jint) * (Sigexit+1), mtInternal); - memset(pending_signals, 0, (sizeof(jint) * (Sigexit+1))); - - if (UseSignalChaining) { - chainedsigactions = (struct sigaction *)malloc(sizeof(struct sigaction) - * (Maxsignum + 1), mtInternal); - memset(chainedsigactions, 0, (sizeof(struct sigaction) * (Maxsignum + 1))); - preinstalled_sigs = (int *)os::malloc(sizeof(int) * (Maxsignum + 1), mtInternal); - memset(preinstalled_sigs, 0, (sizeof(int) * (Maxsignum + 1))); - } - ourSigFlags = (int*)malloc(sizeof(int) * (Maxsignum + 1), mtInternal); - memset(ourSigFlags, 0, sizeof(int) * (Maxsignum + 1)); -} - -static void jdk_misc_signal_init() { - // Initialize signal semaphore - sig_sem = new Semaphore(); -} - -void os::signal_notify(int sig) { - if (sig_sem != NULL) { - Atomic::inc(&pending_signals[sig]); - sig_sem->signal(); - } else { - // Signal thread is not created with ReduceSignalUsage and jdk_misc_signal_init - // initialization isn't called. - assert(ReduceSignalUsage, "signal semaphore should be created"); - } -} - -static int check_pending_signals() { - int ret; - while (true) { - for (int i = 0; i < Sigexit + 1; i++) { - jint n = pending_signals[i]; - if (n > 0 && n == Atomic::cmpxchg(&pending_signals[i], n, n - 1)) { - return i; - } - } - JavaThread *thread = JavaThread::current(); - ThreadBlockInVM tbivm(thread); - - bool threadIsSuspended; - do { - thread->set_suspend_equivalent(); - sig_sem->wait(); - - // were we externally suspended while we were waiting? - threadIsSuspended = thread->handle_special_suspend_equivalent_condition(); - if (threadIsSuspended) { - // The semaphore has been incremented, but while we were waiting - // another thread suspended us. We don't want to continue running - // while suspended because that would surprise the thread that - // suspended us. - sig_sem->signal(); - - thread->java_suspend_self(); - } - } while (threadIsSuspended); - } -} - -int os::signal_wait() { - return check_pending_signals(); -} - -//////////////////////////////////////////////////////////////////////////////// -// Virtual Memory - -static int page_size = -1; - -int os::vm_page_size() { - assert(page_size != -1, "must call os::init"); - return page_size; -} - -// Solaris allocates memory by pages. -int os::vm_allocation_granularity() { - assert(page_size != -1, "must call os::init"); - return page_size; -} - -static bool recoverable_mmap_error(int err) { - // See if the error is one we can let the caller handle. This - // list of errno values comes from the Solaris mmap(2) man page. - switch (err) { - case EBADF: - case EINVAL: - case ENOTSUP: - // let the caller deal with these errors - return true; - - default: - // Any remaining errors on this OS can cause our reserved mapping - // to be lost. That can cause confusion where different data - // structures think they have the same memory mapped. The worst - // scenario is if both the VM and a library think they have the - // same memory mapped. - return false; - } -} - -static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec, - int err) { - warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT - ", %d) failed; error='%s' (errno=%d)", addr, bytes, exec, - os::strerror(err), err); -} - -static void warn_fail_commit_memory(char* addr, size_t bytes, - size_t alignment_hint, bool exec, - int err) { - warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT - ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", addr, bytes, - alignment_hint, exec, os::strerror(err), err); -} - -int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) { - int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; - size_t size = bytes; - char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); - if (res != NULL) { - if (UseNUMAInterleaving) { - numa_make_global(addr, bytes); - } - return 0; - } - - int err = errno; // save errno from mmap() call in mmap_chunk() - - if (!recoverable_mmap_error(err)) { - warn_fail_commit_memory(addr, bytes, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory."); - } - - return err; -} - -bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { - return Solaris::commit_memory_impl(addr, bytes, exec) == 0; -} - -void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec, - const char* mesg) { - assert(mesg != NULL, "mesg must be specified"); - int err = os::Solaris::commit_memory_impl(addr, bytes, exec); - if (err != 0) { - // the caller wants all commit errors to exit with the specified mesg: - warn_fail_commit_memory(addr, bytes, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); - } -} - -size_t os::Solaris::page_size_for_alignment(size_t alignment) { - assert(is_aligned(alignment, (size_t) vm_page_size()), - SIZE_FORMAT " is not aligned to " SIZE_FORMAT, - alignment, (size_t) vm_page_size()); - - for (int i = 0; _page_sizes[i] != 0; i++) { - if (is_aligned(alignment, _page_sizes[i])) { - return _page_sizes[i]; - } - } - - return (size_t) vm_page_size(); -} - -int os::Solaris::commit_memory_impl(char* addr, size_t bytes, - size_t alignment_hint, bool exec) { - int err = Solaris::commit_memory_impl(addr, bytes, exec); - if (err == 0 && UseLargePages && alignment_hint > 0) { - assert(is_aligned(bytes, alignment_hint), - SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint); - - // The syscall memcntl requires an exact page size (see man memcntl for details). - size_t page_size = page_size_for_alignment(alignment_hint); - if (page_size > (size_t) vm_page_size()) { - (void)Solaris::setup_large_pages(addr, bytes, page_size); - } - } - return err; -} - -bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint, - bool exec) { - return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0; -} - -void os::pd_commit_memory_or_exit(char* addr, size_t bytes, - size_t alignment_hint, bool exec, - const char* mesg) { - assert(mesg != NULL, "mesg must be specified"); - int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec); - if (err != 0) { - // the caller wants all commit errors to exit with the specified mesg: - warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); - vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); - } -} - -// Uncommit the pages in a specified region. -void os::pd_free_memory(char* addr, size_t bytes, size_t alignment_hint) { - if (madvise(addr, bytes, MADV_FREE) < 0) { - debug_only(warning("MADV_FREE failed.")); - return; - } -} - -bool os::pd_create_stack_guard_pages(char* addr, size_t size) { - return os::commit_memory(addr, size, !ExecMem); -} - -bool os::remove_stack_guard_pages(char* addr, size_t size) { - return os::uncommit_memory(addr, size); -} - -// Change the page size in a given range. -void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { - assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned."); - assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned."); - if (UseLargePages) { - size_t page_size = Solaris::page_size_for_alignment(alignment_hint); - if (page_size > (size_t) vm_page_size()) { - Solaris::setup_large_pages(addr, bytes, page_size); - } - } -} - -// Tell the OS to make the range local to the first-touching LWP -void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { - assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned."); - if (madvise(addr, bytes, MADV_ACCESS_LWP) < 0) { - debug_only(warning("MADV_ACCESS_LWP failed.")); - } -} - -// Tell the OS that this range would be accessed from different LWPs. -void os::numa_make_global(char *addr, size_t bytes) { - assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned."); - if (madvise(addr, bytes, MADV_ACCESS_MANY) < 0) { - debug_only(warning("MADV_ACCESS_MANY failed.")); - } -} - -// Get the number of the locality groups. -size_t os::numa_get_groups_num() { - size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie()); - return n != -1 ? n : 1; -} - -// Get a list of leaf locality groups. A leaf lgroup is group that -// doesn't have any children. Typical leaf group is a CPU or a CPU/memory -// board. An LWP is assigned to one of these groups upon creation. -size_t os::numa_get_leaf_groups(int *ids, size_t size) { - if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) { - ids[0] = 0; - return 1; - } - int result_size = 0, top = 1, bottom = 0, cur = 0; - for (int k = 0; k < size; k++) { - int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur], - (Solaris::lgrp_id_t*)&ids[top], size - top); - if (r == -1) { - ids[0] = 0; - return 1; - } - if (!r) { - // That's a leaf node. - assert(bottom <= cur, "Sanity check"); - // Check if the node has memory - if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur], - NULL, 0, LGRP_RSRC_MEM) > 0) { - ids[bottom++] = ids[cur]; - } - } - top += r; - cur++; - } - if (bottom == 0) { - // Handle a situation, when the OS reports no memory available. - // Assume UMA architecture. - ids[0] = 0; - return 1; - } - return bottom; -} - -// Detect the topology change. Typically happens during CPU plugging-unplugging. -bool os::numa_topology_changed() { - int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie()); - if (is_stale != -1 && is_stale) { - Solaris::lgrp_fini(Solaris::lgrp_cookie()); - Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER); - assert(c != 0, "Failure to initialize LGRP API"); - Solaris::set_lgrp_cookie(c); - return true; - } - return false; -} - -// Get the group id of the current LWP. -int os::numa_get_group_id() { - int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID); - if (lgrp_id == -1) { - return 0; - } - const int size = os::numa_get_groups_num(); - int *ids = (int*)alloca(size * sizeof(int)); - - // Get the ids of all lgroups with memory; r is the count. - int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id, - (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM); - if (r <= 0) { - return 0; - } - return ids[os::random() % r]; -} - -int os::numa_get_group_id_for_address(const void* address) { - return 0; -} - -// Request information about the page. -bool os::get_page_info(char *start, page_info* info) { - const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; - uint64_t addr = (uintptr_t)start; - uint64_t outdata[2]; - uint_t validity = 0; - - if (meminfo(&addr, 1, info_types, 2, outdata, &validity) < 0) { - return false; - } - - info->size = 0; - info->lgrp_id = -1; - - if ((validity & 1) != 0) { - if ((validity & 2) != 0) { - info->lgrp_id = outdata[0]; - } - if ((validity & 4) != 0) { - info->size = outdata[1]; - } - return true; - } - return false; -} - -// Scan the pages from start to end until a page different than -// the one described in the info parameter is encountered. -char *os::scan_pages(char *start, char* end, page_info* page_expected, - page_info* page_found) { - const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; - const size_t types = sizeof(info_types) / sizeof(info_types[0]); - uint64_t addrs[MAX_MEMINFO_CNT], outdata[types * MAX_MEMINFO_CNT + 1]; - uint_t validity[MAX_MEMINFO_CNT]; - - size_t page_size = MAX2((size_t)os::vm_page_size(), page_expected->size); - uint64_t p = (uint64_t)start; - while (p < (uint64_t)end) { - addrs[0] = p; - size_t addrs_count = 1; - while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) { - addrs[addrs_count] = addrs[addrs_count - 1] + page_size; - addrs_count++; - } - - if (meminfo(addrs, addrs_count, info_types, types, outdata, validity) < 0) { - return NULL; - } - - size_t i = 0; - for (; i < addrs_count; i++) { - if ((validity[i] & 1) != 0) { - if ((validity[i] & 4) != 0) { - if (outdata[types * i + 1] != page_expected->size) { - break; - } - } else if (page_expected->size != 0) { - break; - } - - if ((validity[i] & 2) != 0 && page_expected->lgrp_id > 0) { - if (outdata[types * i] != page_expected->lgrp_id) { - break; - } - } - } else { - return NULL; - } - } - - if (i < addrs_count) { - if ((validity[i] & 2) != 0) { - page_found->lgrp_id = outdata[types * i]; - } else { - page_found->lgrp_id = -1; - } - if ((validity[i] & 4) != 0) { - page_found->size = outdata[types * i + 1]; - } else { - page_found->size = 0; - } - return (char*)addrs[i]; - } - - p = addrs[addrs_count - 1] + page_size; - } - return end; -} - -bool os::pd_uncommit_memory(char* addr, size_t bytes) { - size_t size = bytes; - // Map uncommitted pages PROT_NONE so we fail early if we touch an - // uncommitted page. Otherwise, the read/write might succeed if we - // have enough swap space to back the physical page. - return - NULL != Solaris::mmap_chunk(addr, size, - MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE, - PROT_NONE); -} - -char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) { - char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0); - - if (b == MAP_FAILED) { - return NULL; - } - return b; -} - -char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes, - size_t alignment_hint, bool fixed) { - char* addr = requested_addr; - int flags = MAP_PRIVATE | MAP_NORESERVE; - - assert(!(fixed && (alignment_hint > 0)), - "alignment hint meaningless with fixed mmap"); - - if (fixed) { - flags |= MAP_FIXED; - } else if (alignment_hint > (size_t) vm_page_size()) { - flags |= MAP_ALIGN; - addr = (char*) alignment_hint; - } - - // Map uncommitted pages PROT_NONE so we fail early if we touch an - // uncommitted page. Otherwise, the read/write might succeed if we - // have enough swap space to back the physical page. - return mmap_chunk(addr, bytes, flags, PROT_NONE); -} - -char* os::pd_reserve_memory(size_t bytes, char* requested_addr, - size_t alignment_hint) { - char* addr = Solaris::anon_mmap(requested_addr, bytes, alignment_hint, - (requested_addr != NULL)); - - guarantee(requested_addr == NULL || requested_addr == addr, - "OS failed to return requested mmap address."); - return addr; -} - -char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr, int file_desc) { - assert(file_desc >= 0, "file_desc is not valid"); - char* result = pd_attempt_reserve_memory_at(bytes, requested_addr); - if (result != NULL) { - if (replace_existing_mapping_with_file_mapping(result, bytes, file_desc) == NULL) { - vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory")); - } - } - return result; -} - -// Reserve memory at an arbitrary address, only if that area is -// available (and not reserved for something else). - -char* os::pd_attempt_reserve_memory_at(size_t bytes, char* requested_addr) { - // Assert only that the size is a multiple of the page size, since - // that's all that mmap requires, and since that's all we really know - // about at this low abstraction level. If we need higher alignment, - // we can either pass an alignment to this method or verify alignment - // in one of the methods further up the call chain. See bug 5044738. - assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block"); - - // Since snv_84, Solaris attempts to honor the address hint - see 5003415. - char* addr = Solaris::anon_mmap(requested_addr, bytes, 0, false); - - volatile int err = errno; - if (addr == requested_addr) { - return addr; - } - - if (addr != NULL) { - pd_unmap_memory(addr, bytes); - } - - return NULL; -} - -bool os::pd_release_memory(char* addr, size_t bytes) { - size_t size = bytes; - return munmap(addr, size) == 0; -} - -static bool solaris_mprotect(char* addr, size_t bytes, int prot) { - assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()), - "addr must be page aligned"); - Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot); - int retVal = mprotect(addr, bytes, prot); - return retVal == 0; -} - -// Protect memory (Used to pass readonly pages through -// JNI GetArrayElements with empty arrays.) -// Also, used for serialization page and for compressed oops null pointer -// checking. -bool os::protect_memory(char* addr, size_t bytes, ProtType prot, - bool is_committed) { - unsigned int p = 0; - switch (prot) { - case MEM_PROT_NONE: p = PROT_NONE; break; - case MEM_PROT_READ: p = PROT_READ; break; - case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break; - case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break; - default: - ShouldNotReachHere(); - } - // is_committed is unused. - return solaris_mprotect(addr, bytes, p); -} - -// guard_memory and unguard_memory only happens within stack guard pages. -// Since ISM pertains only to the heap, guard and unguard memory should not -/// happen with an ISM region. -bool os::guard_memory(char* addr, size_t bytes) { - return solaris_mprotect(addr, bytes, PROT_NONE); -} - -bool os::unguard_memory(char* addr, size_t bytes) { - return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE); -} - -// Large page support -static size_t _large_page_size = 0; - -// Insertion sort for small arrays (descending order). -static void insertion_sort_descending(size_t* array, int len) { - for (int i = 0; i < len; i++) { - size_t val = array[i]; - for (size_t key = i; key > 0 && array[key - 1] < val; --key) { - size_t tmp = array[key]; - array[key] = array[key - 1]; - array[key - 1] = tmp; - } - } -} - -bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) { - const unsigned int usable_count = VM_Version::page_size_count(); - if (usable_count == 1) { - return false; - } - - // Find the right getpagesizes interface. When solaris 11 is the minimum - // build platform, getpagesizes() (without the '2') can be called directly. - typedef int (*gps_t)(size_t[], int); - gps_t gps_func = CAST_TO_FN_PTR(gps_t, dlsym(RTLD_DEFAULT, "getpagesizes2")); - if (gps_func == NULL) { - gps_func = CAST_TO_FN_PTR(gps_t, dlsym(RTLD_DEFAULT, "getpagesizes")); - if (gps_func == NULL) { - if (warn) { - warning("MPSS is not supported by the operating system."); - } - return false; - } - } - - // Fill the array of page sizes. - int n = (*gps_func)(_page_sizes, page_sizes_max); - assert(n > 0, "Solaris bug?"); - - if (n == page_sizes_max) { - // Add a sentinel value (necessary only if the array was completely filled - // since it is static (zeroed at initialization)). - _page_sizes[--n] = 0; - DEBUG_ONLY(warning("increase the size of the os::_page_sizes array.");) - } - assert(_page_sizes[n] == 0, "missing sentinel"); - trace_page_sizes("available page sizes", _page_sizes, n); - - if (n == 1) return false; // Only one page size available. - - // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set) and - // select up to usable_count elements. First sort the array, find the first - // acceptable value, then copy the usable sizes to the top of the array and - // trim the rest. Make sure to include the default page size :-). - // - // A better policy could get rid of the 4M limit by taking the sizes of the - // important VM memory regions (java heap and possibly the code cache) into - // account. - insertion_sort_descending(_page_sizes, n); - const size_t size_limit = - FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes; - int beg; - for (beg = 0; beg < n && _page_sizes[beg] > size_limit; ++beg) /* empty */; - const int end = MIN2((int)usable_count, n) - 1; - for (int cur = 0; cur < end; ++cur, ++beg) { - _page_sizes[cur] = _page_sizes[beg]; - } - _page_sizes[end] = vm_page_size(); - _page_sizes[end + 1] = 0; - - if (_page_sizes[end] > _page_sizes[end - 1]) { - // Default page size is not the smallest; sort again. - insertion_sort_descending(_page_sizes, end + 1); - } - *page_size = _page_sizes[0]; - - trace_page_sizes("usable page sizes", _page_sizes, end + 1); - return true; -} - -void os::large_page_init() { - if (UseLargePages) { - // print a warning if any large page related flag is specified on command line - bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || - !FLAG_IS_DEFAULT(LargePageSizeInBytes); - - UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size); - } -} - -bool os::Solaris::is_valid_page_size(size_t bytes) { - for (int i = 0; _page_sizes[i] != 0; i++) { - if (_page_sizes[i] == bytes) { - return true; - } - } - return false; -} - -bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { - assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align); - assert(is_aligned((void*) start, align), - PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align); - assert(is_aligned(bytes, align), - SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align); - - // Signal to OS that we want large pages for addresses - // from addr, addr + bytes - struct memcntl_mha mpss_struct; - mpss_struct.mha_cmd = MHA_MAPSIZE_VA; - mpss_struct.mha_pagesize = align; - mpss_struct.mha_flags = 0; - // Upon successful completion, memcntl() returns 0 - if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) { - debug_only(warning("Attempt to use MPSS failed.")); - return false; - } - return true; -} - -char* os::pd_reserve_memory_special(size_t size, size_t alignment, char* addr, bool exec) { - fatal("os::reserve_memory_special should not be called on Solaris."); - return NULL; -} - -bool os::pd_release_memory_special(char* base, size_t bytes) { - fatal("os::release_memory_special should not be called on Solaris."); - return false; -} - -size_t os::large_page_size() { - return _large_page_size; -} - -// MPSS allows application to commit large page memory on demand; with ISM -// the entire memory region must be allocated as shared memory. -bool os::can_commit_large_page_memory() { - return true; -} - -bool os::can_execute_large_page_memory() { - return true; -} - -// Sleep forever; naked call to OS-specific sleep; use with CAUTION -void os::infinite_sleep() { - while (true) { // sleep forever ... - ::sleep(100); // ... 100 seconds at a time - } -} - -// Used to convert frequent JVM_Yield() to nops -bool os::dont_yield() { - if (DontYieldALot) { - static hrtime_t last_time = 0; - hrtime_t diff = getTimeNanos() - last_time; - - if (diff < DontYieldALotInterval * 1000000) { - return true; - } - - last_time += diff; - - return false; - } else { - return false; - } -} - -// Note that yield semantics are defined by the scheduling class to which -// the thread currently belongs. Typically, yield will _not yield to -// other equal or higher priority threads that reside on the dispatch queues -// of other CPUs. - -void os::naked_yield() { - thr_yield(); -} - -// Interface for setting lwp priorities. We are using T2 libthread, -// which forces the use of bound threads, so all of our threads will -// be assigned to real lwp's. Using the thr_setprio function is -// meaningless in this mode so we must adjust the real lwp's priority. -// The routines below implement the getting and setting of lwp priorities. -// -// Note: There are three priority scales used on Solaris. Java priotities -// which range from 1 to 10, libthread "thr_setprio" scale which range -// from 0 to 127, and the current scheduling class of the process we -// are running in. This is typically from -60 to +60. -// The setting of the lwp priorities in done after a call to thr_setprio -// so Java priorities are mapped to libthread priorities and we map from -// the latter to lwp priorities. We don't keep priorities stored in -// Java priorities since some of our worker threads want to set priorities -// higher than all Java threads. -// -// For related information: -// (1) man -s 2 priocntl -// (2) man -s 4 priocntl -// (3) man dispadmin -// = librt.so -// = libthread/common/rtsched.c - thrp_setlwpprio(). -// = ps -cL ... to validate priority. -// = sched_get_priority_min and _max -// pthread_create -// sched_setparam -// pthread_setschedparam -// -// Assumptions: -// + We assume that all threads in the process belong to the same -// scheduling class. IE. an homogenous process. -// + Must be root or in IA group to change change "interactive" attribute. -// Priocntl() will fail silently. The only indication of failure is when -// we read-back the value and notice that it hasn't changed. -// + Interactive threads enter the runq at the head, non-interactive at the tail. -// + For RT, change timeslice as well. Invariant: -// constant "priority integral" -// Konst == TimeSlice * (60-Priority) -// Given a priority, compute appropriate timeslice. -// + Higher numerical values have higher priority. - -// sched class attributes -typedef struct { - int schedPolicy; // classID - int maxPrio; - int minPrio; -} SchedInfo; - - -static SchedInfo tsLimits, iaLimits, rtLimits, fxLimits; - -#ifdef ASSERT -static int ReadBackValidate = 1; -#endif -static int myClass = 0; -static int myMin = 0; -static int myMax = 0; -static int myCur = 0; -static bool priocntl_enable = false; - -static const int criticalPrio = FXCriticalPriority; -static int java_MaxPriority_to_os_priority = 0; // Saved mapping - - -// lwp_priocntl_init -// -// Try to determine the priority scale for our process. -// -// Return errno or 0 if OK. -// -static int lwp_priocntl_init() { - int rslt; - pcinfo_t ClassInfo; - pcparms_t ParmInfo; - int i; - - if (!UseThreadPriorities) return 0; - - // If ThreadPriorityPolicy is 1, switch tables - if (ThreadPriorityPolicy == 1) { - for (i = 0; i < CriticalPriority+1; i++) - os::java_to_os_priority[i] = prio_policy1[i]; - } - if (UseCriticalJavaThreadPriority) { - // MaxPriority always maps to the FX scheduling class and criticalPrio. - // See set_native_priority() and set_lwp_class_and_priority(). - // Save original MaxPriority mapping in case attempt to - // use critical priority fails. - java_MaxPriority_to_os_priority = os::java_to_os_priority[MaxPriority]; - // Set negative to distinguish from other priorities - os::java_to_os_priority[MaxPriority] = -criticalPrio; - } - - // Get IDs for a set of well-known scheduling classes. - // TODO-FIXME: GETCLINFO returns the current # of classes in the - // the system. We should have a loop that iterates over the - // classID values, which are known to be "small" integers. - - strcpy(ClassInfo.pc_clname, "TS"); - ClassInfo.pc_cid = -1; - rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); - if (rslt < 0) return errno; - assert(ClassInfo.pc_cid != -1, "cid for TS class is -1"); - tsLimits.schedPolicy = ClassInfo.pc_cid; - tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri; - tsLimits.minPrio = -tsLimits.maxPrio; - - strcpy(ClassInfo.pc_clname, "IA"); - ClassInfo.pc_cid = -1; - rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); - if (rslt < 0) return errno; - assert(ClassInfo.pc_cid != -1, "cid for IA class is -1"); - iaLimits.schedPolicy = ClassInfo.pc_cid; - iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri; - iaLimits.minPrio = -iaLimits.maxPrio; - - strcpy(ClassInfo.pc_clname, "RT"); - ClassInfo.pc_cid = -1; - rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); - if (rslt < 0) return errno; - assert(ClassInfo.pc_cid != -1, "cid for RT class is -1"); - rtLimits.schedPolicy = ClassInfo.pc_cid; - rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri; - rtLimits.minPrio = 0; - - strcpy(ClassInfo.pc_clname, "FX"); - ClassInfo.pc_cid = -1; - rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); - if (rslt < 0) return errno; - assert(ClassInfo.pc_cid != -1, "cid for FX class is -1"); - fxLimits.schedPolicy = ClassInfo.pc_cid; - fxLimits.maxPrio = ((fxinfo_t*)ClassInfo.pc_clinfo)->fx_maxupri; - fxLimits.minPrio = 0; - - // Query our "current" scheduling class. - // This will normally be IA, TS or, rarely, FX or RT. - memset(&ParmInfo, 0, sizeof(ParmInfo)); - ParmInfo.pc_cid = PC_CLNULL; - rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo); - if (rslt < 0) return errno; - myClass = ParmInfo.pc_cid; - - // We now know our scheduling classId, get specific information - // about the class. - ClassInfo.pc_cid = myClass; - ClassInfo.pc_clname[0] = 0; - rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo); - if (rslt < 0) return errno; - - if (ThreadPriorityVerbose) { - tty->print_cr("lwp_priocntl_init: Class=%d(%s)...", myClass, ClassInfo.pc_clname); - } - - memset(&ParmInfo, 0, sizeof(pcparms_t)); - ParmInfo.pc_cid = PC_CLNULL; - rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo); - if (rslt < 0) return errno; - - if (ParmInfo.pc_cid == rtLimits.schedPolicy) { - myMin = rtLimits.minPrio; - myMax = rtLimits.maxPrio; - } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) { - iaparms_t *iaInfo = (iaparms_t*)ParmInfo.pc_clparms; - myMin = iaLimits.minPrio; - myMax = iaLimits.maxPrio; - myMax = MIN2(myMax, (int)iaInfo->ia_uprilim); // clamp - restrict - } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) { - tsparms_t *tsInfo = (tsparms_t*)ParmInfo.pc_clparms; - myMin = tsLimits.minPrio; - myMax = tsLimits.maxPrio; - myMax = MIN2(myMax, (int)tsInfo->ts_uprilim); // clamp - restrict - } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) { - fxparms_t *fxInfo = (fxparms_t*)ParmInfo.pc_clparms; - myMin = fxLimits.minPrio; - myMax = fxLimits.maxPrio; - myMax = MIN2(myMax, (int)fxInfo->fx_uprilim); // clamp - restrict - } else { - // No clue - punt - if (ThreadPriorityVerbose) { - tty->print_cr("Unknown scheduling class: %s ... \n", - ClassInfo.pc_clname); - } - return EINVAL; // no clue, punt - } - - if (ThreadPriorityVerbose) { - tty->print_cr("Thread priority Range: [%d..%d]\n", myMin, myMax); - } - - priocntl_enable = true; // Enable changing priorities - return 0; -} - -#define IAPRI(x) ((iaparms_t *)((x).pc_clparms)) -#define RTPRI(x) ((rtparms_t *)((x).pc_clparms)) -#define TSPRI(x) ((tsparms_t *)((x).pc_clparms)) -#define FXPRI(x) ((fxparms_t *)((x).pc_clparms)) - - -// scale_to_lwp_priority -// -// Convert from the libthread "thr_setprio" scale to our current -// lwp scheduling class scale. -// -static int scale_to_lwp_priority(int rMin, int rMax, int x) { - int v; - - if (x == 127) return rMax; // avoid round-down - v = (((x*(rMax-rMin)))/128)+rMin; - return v; -} - - -// set_lwp_class_and_priority -int set_lwp_class_and_priority(int ThreadID, int lwpid, - int newPrio, int new_class, bool scale) { - int rslt; - int Actual, Expected, prv; - pcparms_t ParmInfo; // for GET-SET -#ifdef ASSERT - pcparms_t ReadBack; // for readback -#endif - - // Set priority via PC_GETPARMS, update, PC_SETPARMS - // Query current values. - // TODO: accelerate this by eliminating the PC_GETPARMS call. - // Cache "pcparms_t" in global ParmCache. - // TODO: elide set-to-same-value - - // If something went wrong on init, don't change priorities. - if (!priocntl_enable) { - if (ThreadPriorityVerbose) { - tty->print_cr("Trying to set priority but init failed, ignoring"); - } - return EINVAL; - } - - // If lwp hasn't started yet, just return - // the _start routine will call us again. - if (lwpid <= 0) { - if (ThreadPriorityVerbose) { - tty->print_cr("deferring the set_lwp_class_and_priority of thread " - INTPTR_FORMAT " to %d, lwpid not set", - ThreadID, newPrio); - } - return 0; - } - - if (ThreadPriorityVerbose) { - tty->print_cr ("set_lwp_class_and_priority(" - INTPTR_FORMAT "@" INTPTR_FORMAT " %d) ", - ThreadID, lwpid, newPrio); - } - - memset(&ParmInfo, 0, sizeof(pcparms_t)); - ParmInfo.pc_cid = PC_CLNULL; - rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo); - if (rslt < 0) return errno; - - int cur_class = ParmInfo.pc_cid; - ParmInfo.pc_cid = (id_t)new_class; - - if (new_class == rtLimits.schedPolicy) { - rtparms_t *rtInfo = (rtparms_t*)ParmInfo.pc_clparms; - rtInfo->rt_pri = scale ? scale_to_lwp_priority(rtLimits.minPrio, - rtLimits.maxPrio, newPrio) - : newPrio; - rtInfo->rt_tqsecs = RT_NOCHANGE; - rtInfo->rt_tqnsecs = RT_NOCHANGE; - if (ThreadPriorityVerbose) { - tty->print_cr("RT: %d->%d\n", newPrio, rtInfo->rt_pri); - } - } else if (new_class == iaLimits.schedPolicy) { - iaparms_t* iaInfo = (iaparms_t*)ParmInfo.pc_clparms; - int maxClamped = MIN2(iaLimits.maxPrio, - cur_class == new_class - ? (int)iaInfo->ia_uprilim : iaLimits.maxPrio); - iaInfo->ia_upri = scale ? scale_to_lwp_priority(iaLimits.minPrio, - maxClamped, newPrio) - : newPrio; - iaInfo->ia_uprilim = cur_class == new_class - ? IA_NOCHANGE : (pri_t)iaLimits.maxPrio; - iaInfo->ia_mode = IA_NOCHANGE; - if (ThreadPriorityVerbose) { - tty->print_cr("IA: [%d...%d] %d->%d\n", - iaLimits.minPrio, maxClamped, newPrio, iaInfo->ia_upri); - } - } else if (new_class == tsLimits.schedPolicy) { - tsparms_t* tsInfo = (tsparms_t*)ParmInfo.pc_clparms; - int maxClamped = MIN2(tsLimits.maxPrio, - cur_class == new_class - ? (int)tsInfo->ts_uprilim : tsLimits.maxPrio); - tsInfo->ts_upri = scale ? scale_to_lwp_priority(tsLimits.minPrio, - maxClamped, newPrio) - : newPrio; - tsInfo->ts_uprilim = cur_class == new_class - ? TS_NOCHANGE : (pri_t)tsLimits.maxPrio; - if (ThreadPriorityVerbose) { - tty->print_cr("TS: [%d...%d] %d->%d\n", - tsLimits.minPrio, maxClamped, newPrio, tsInfo->ts_upri); - } - } else if (new_class == fxLimits.schedPolicy) { - fxparms_t* fxInfo = (fxparms_t*)ParmInfo.pc_clparms; - int maxClamped = MIN2(fxLimits.maxPrio, - cur_class == new_class - ? (int)fxInfo->fx_uprilim : fxLimits.maxPrio); - fxInfo->fx_upri = scale ? scale_to_lwp_priority(fxLimits.minPrio, - maxClamped, newPrio) - : newPrio; - fxInfo->fx_uprilim = cur_class == new_class - ? FX_NOCHANGE : (pri_t)fxLimits.maxPrio; - fxInfo->fx_tqsecs = FX_NOCHANGE; - fxInfo->fx_tqnsecs = FX_NOCHANGE; - if (ThreadPriorityVerbose) { - tty->print_cr("FX: [%d...%d] %d->%d\n", - fxLimits.minPrio, maxClamped, newPrio, fxInfo->fx_upri); - } - } else { - if (ThreadPriorityVerbose) { - tty->print_cr("Unknown new scheduling class %d\n", new_class); - } - return EINVAL; // no clue, punt - } - - rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo); - if (ThreadPriorityVerbose && rslt) { - tty->print_cr ("PC_SETPARMS ->%d %d\n", rslt, errno); - } - if (rslt < 0) return errno; - -#ifdef ASSERT - // Sanity check: read back what we just attempted to set. - // In theory it could have changed in the interim ... - // - // The priocntl system call is tricky. - // Sometimes it'll validate the priority value argument and - // return EINVAL if unhappy. At other times it fails silently. - // Readbacks are prudent. - - if (!ReadBackValidate) return 0; - - memset(&ReadBack, 0, sizeof(pcparms_t)); - ReadBack.pc_cid = PC_CLNULL; - rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack); - assert(rslt >= 0, "priocntl failed"); - Actual = Expected = 0xBAD; - assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match"); - if (ParmInfo.pc_cid == rtLimits.schedPolicy) { - Actual = RTPRI(ReadBack)->rt_pri; - Expected = RTPRI(ParmInfo)->rt_pri; - } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) { - Actual = IAPRI(ReadBack)->ia_upri; - Expected = IAPRI(ParmInfo)->ia_upri; - } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) { - Actual = TSPRI(ReadBack)->ts_upri; - Expected = TSPRI(ParmInfo)->ts_upri; - } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) { - Actual = FXPRI(ReadBack)->fx_upri; - Expected = FXPRI(ParmInfo)->fx_upri; - } else { - if (ThreadPriorityVerbose) { - tty->print_cr("set_lwp_class_and_priority: unexpected class in readback: %d\n", - ParmInfo.pc_cid); - } - } - - if (Actual != Expected) { - if (ThreadPriorityVerbose) { - tty->print_cr ("set_lwp_class_and_priority(%d %d) Class=%d: actual=%d vs expected=%d\n", - lwpid, newPrio, ReadBack.pc_cid, Actual, Expected); - } - } -#endif - - return 0; -} - -// Solaris only gives access to 128 real priorities at a time, -// so we expand Java's ten to fill this range. This would be better -// if we dynamically adjusted relative priorities. -// -// The ThreadPriorityPolicy option allows us to select 2 different -// priority scales. -// -// ThreadPriorityPolicy=0 -// Since the Solaris' default priority is MaximumPriority, we do not -// set a priority lower than Max unless a priority lower than -// NormPriority is requested. -// -// ThreadPriorityPolicy=1 -// This mode causes the priority table to get filled with -// linear values. NormPriority get's mapped to 50% of the -// Maximum priority an so on. This will cause VM threads -// to get unfair treatment against other Solaris processes -// which do not explicitly alter their thread priorities. - -int os::java_to_os_priority[CriticalPriority + 1] = { - -99999, // 0 Entry should never be used - - 0, // 1 MinPriority - 32, // 2 - 64, // 3 - - 96, // 4 - 127, // 5 NormPriority - 127, // 6 - - 127, // 7 - 127, // 8 - 127, // 9 NearMaxPriority - - 127, // 10 MaxPriority - - -criticalPrio // 11 CriticalPriority -}; - -OSReturn os::set_native_priority(Thread* thread, int newpri) { - OSThread* osthread = thread->osthread(); - - // Save requested priority in case the thread hasn't been started - osthread->set_native_priority(newpri); - - // Check for critical priority request - bool fxcritical = false; - if (newpri == -criticalPrio) { - fxcritical = true; - newpri = criticalPrio; - } - - assert(newpri >= MinimumPriority && newpri <= MaximumPriority, "bad priority mapping"); - if (!UseThreadPriorities) return OS_OK; - - int status = 0; - - if (!fxcritical) { - // Use thr_setprio only if we have a priority that thr_setprio understands - status = thr_setprio(thread->osthread()->thread_id(), newpri); - } - - int lwp_status = - set_lwp_class_and_priority(osthread->thread_id(), - osthread->lwp_id(), - newpri, - fxcritical ? fxLimits.schedPolicy : myClass, - !fxcritical); - if (lwp_status != 0 && fxcritical) { - // Try again, this time without changing the scheduling class - newpri = java_MaxPriority_to_os_priority; - lwp_status = set_lwp_class_and_priority(osthread->thread_id(), - osthread->lwp_id(), - newpri, myClass, false); - } - status |= lwp_status; - return (status == 0) ? OS_OK : OS_ERR; -} - - -OSReturn os::get_native_priority(const Thread* const thread, - int *priority_ptr) { - int p; - if (!UseThreadPriorities) { - *priority_ptr = NormalPriority; - return OS_OK; - } - int status = thr_getprio(thread->osthread()->thread_id(), &p); - if (status != 0) { - return OS_ERR; - } - *priority_ptr = p; - return OS_OK; -} - -//////////////////////////////////////////////////////////////////////////////// -// suspend/resume support - -// The low-level signal-based suspend/resume support is a remnant from the -// old VM-suspension that used to be for java-suspension, safepoints etc, -// within hotspot. Currently used by JFR's OSThreadSampler -// -// The remaining code is greatly simplified from the more general suspension -// code that used to be used. -// -// The protocol is quite simple: -// - suspend: -// - sends a signal to the target thread -// - polls the suspend state of the osthread using a yield loop -// - target thread signal handler (SR_handler) sets suspend state -// and blocks in sigsuspend until continued -// - resume: -// - sets target osthread state to continue -// - sends signal to end the sigsuspend loop in the SR_handler -// -// Note that the SR_lock plays no role in this suspend/resume protocol, -// but is checked for NULL in SR_handler as a thread termination indicator. -// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs. -// -// Note that resume_clear_context() and suspend_save_context() are needed -// by SR_handler(), so that fetch_frame_from_ucontext() works, -// which in part is used by: -// - Forte Analyzer: AsyncGetCallTrace() -// - StackBanging: get_frame_at_stack_banging_point() -// - JFR: get_topframe()-->....-->get_valid_uc_in_signal_handler() - -static void resume_clear_context(OSThread *osthread) { - osthread->set_ucontext(NULL); -} - -static void suspend_save_context(OSThread *osthread, ucontext_t* context) { - osthread->set_ucontext(context); -} - -static PosixSemaphore sr_semaphore; - -void os::Solaris::SR_handler(Thread* thread, ucontext_t* context) { - // Save and restore errno to avoid confusing native code with EINTR - // after sigsuspend. - int old_errno = errno; - - OSThread* osthread = thread->osthread(); - assert(thread->is_VM_thread() || thread->is_Java_thread(), "Must be VMThread or JavaThread"); - - os::SuspendResume::State current = osthread->sr.state(); - if (current == os::SuspendResume::SR_SUSPEND_REQUEST) { - suspend_save_context(osthread, context); - - // attempt to switch the state, we assume we had a SUSPEND_REQUEST - os::SuspendResume::State state = osthread->sr.suspended(); - if (state == os::SuspendResume::SR_SUSPENDED) { - sigset_t suspend_set; // signals for sigsuspend() - - // get current set of blocked signals and unblock resume signal - pthread_sigmask(SIG_BLOCK, NULL, &suspend_set); - sigdelset(&suspend_set, ASYNC_SIGNAL); - - sr_semaphore.signal(); - // wait here until we are resumed - while (1) { - sigsuspend(&suspend_set); - - os::SuspendResume::State result = osthread->sr.running(); - if (result == os::SuspendResume::SR_RUNNING) { - sr_semaphore.signal(); - break; - } - } - - } else if (state == os::SuspendResume::SR_RUNNING) { - // request was cancelled, continue - } else { - ShouldNotReachHere(); - } - - resume_clear_context(osthread); - } else if (current == os::SuspendResume::SR_RUNNING) { - // request was cancelled, continue - } else if (current == os::SuspendResume::SR_WAKEUP_REQUEST) { - // ignore - } else { - // ignore - } - - errno = old_errno; -} - -void os::print_statistics() { -} - -bool os::message_box(const char* title, const char* message) { - int i; - fdStream err(defaultStream::error_fd()); - for (i = 0; i < 78; i++) err.print_raw("="); - err.cr(); - err.print_raw_cr(title); - for (i = 0; i < 78; i++) err.print_raw("-"); - err.cr(); - err.print_raw_cr(message); - for (i = 0; i < 78; i++) err.print_raw("="); - err.cr(); - - char buf[16]; - // Prevent process from exiting upon "read error" without consuming all CPU - while (::read(0, buf, sizeof(buf)) <= 0) { ::sleep(100); } - - return buf[0] == 'y' || buf[0] == 'Y'; -} - -static int sr_notify(OSThread* osthread) { - int status = thr_kill(osthread->thread_id(), ASYNC_SIGNAL); - assert_status(status == 0, status, "thr_kill"); - return status; -} - -// "Randomly" selected value for how long we want to spin -// before bailing out on suspending a thread, also how often -// we send a signal to a thread we want to resume -static const int RANDOMLY_LARGE_INTEGER = 1000000; -static const int RANDOMLY_LARGE_INTEGER2 = 100; - -static bool do_suspend(OSThread* osthread) { - assert(osthread->sr.is_running(), "thread should be running"); - assert(!sr_semaphore.trywait(), "semaphore has invalid state"); - - // mark as suspended and send signal - if (osthread->sr.request_suspend() != os::SuspendResume::SR_SUSPEND_REQUEST) { - // failed to switch, state wasn't running? - ShouldNotReachHere(); - return false; - } - - if (sr_notify(osthread) != 0) { - ShouldNotReachHere(); - } - - // managed to send the signal and switch to SUSPEND_REQUEST, now wait for SUSPENDED - while (true) { - if (sr_semaphore.timedwait(2000)) { - break; - } else { - // timeout - os::SuspendResume::State cancelled = osthread->sr.cancel_suspend(); - if (cancelled == os::SuspendResume::SR_RUNNING) { - return false; - } else if (cancelled == os::SuspendResume::SR_SUSPENDED) { - // make sure that we consume the signal on the semaphore as well - sr_semaphore.wait(); - break; - } else { - ShouldNotReachHere(); - return false; - } - } - } - - guarantee(osthread->sr.is_suspended(), "Must be suspended"); - return true; -} - -static void do_resume(OSThread* osthread) { - assert(osthread->sr.is_suspended(), "thread should be suspended"); - assert(!sr_semaphore.trywait(), "invalid semaphore state"); - - if (osthread->sr.request_wakeup() != os::SuspendResume::SR_WAKEUP_REQUEST) { - // failed to switch to WAKEUP_REQUEST - ShouldNotReachHere(); - return; - } - - while (true) { - if (sr_notify(osthread) == 0) { - if (sr_semaphore.timedwait(2)) { - if (osthread->sr.is_running()) { - return; - } - } - } else { - ShouldNotReachHere(); - } - } - - guarantee(osthread->sr.is_running(), "Must be running!"); -} - -void os::SuspendedThreadTask::internal_do_task() { - if (do_suspend(_thread->osthread())) { - SuspendedThreadTaskContext context(_thread, _thread->osthread()->ucontext()); - do_task(context); - do_resume(_thread->osthread()); - } -} - -// This does not do anything on Solaris. This is basically a hook for being -// able to use structured exception handling (thread-local exception filters) on, e.g., Win32. -void os::os_exception_wrapper(java_call_t f, JavaValue* value, - const methodHandle& method, JavaCallArguments* args, - Thread* thread) { - f(value, method, args, thread); -} - -// This routine may be used by user applications as a "hook" to catch signals. -// The user-defined signal handler must pass unrecognized signals to this -// routine, and if it returns true (non-zero), then the signal handler must -// return immediately. If the flag "abort_if_unrecognized" is true, then this -// routine will never retun false (zero), but instead will execute a VM panic -// routine kill the process. -// -// If this routine returns false, it is OK to call it again. This allows -// the user-defined signal handler to perform checks either before or after -// the VM performs its own checks. Naturally, the user code would be making -// a serious error if it tried to handle an exception (such as a null check -// or breakpoint) that the VM was generating for its own correct operation. -// -// This routine may recognize any of the following kinds of signals: -// SIGBUS, SIGSEGV, SIGILL, SIGFPE, BREAK_SIGNAL, SIGPIPE, SIGXFSZ, -// ASYNC_SIGNAL. -// It should be consulted by handlers for any of those signals. -// -// The caller of this routine must pass in the three arguments supplied -// to the function referred to in the "sa_sigaction" (not the "sa_handler") -// field of the structure passed to sigaction(). This routine assumes that -// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART. -// -// Note that the VM will print warnings if it detects conflicting signal -// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers". -// -extern "C" JNIEXPORT int JVM_handle_solaris_signal(int signo, - siginfo_t* siginfo, - void* ucontext, - int abort_if_unrecognized); - - -void signalHandler(int sig, siginfo_t* info, void* ucVoid) { - int orig_errno = errno; // Preserve errno value over signal handler. - JVM_handle_solaris_signal(sig, info, ucVoid, true); - errno = orig_errno; -} - -// This boolean allows users to forward their own non-matching signals -// to JVM_handle_solaris_signal, harmlessly. -bool os::Solaris::signal_handlers_are_installed = false; - -// For signal-chaining -bool os::Solaris::libjsig_is_loaded = false; -typedef struct sigaction *(*get_signal_t)(int); -get_signal_t os::Solaris::get_signal_action = NULL; - -struct sigaction* os::Solaris::get_chained_signal_action(int sig) { - struct sigaction *actp = NULL; - - if ((libjsig_is_loaded) && (sig <= Maxsignum)) { - // Retrieve the old signal handler from libjsig - actp = (*get_signal_action)(sig); - } - if (actp == NULL) { - // Retrieve the preinstalled signal handler from jvm - actp = get_preinstalled_handler(sig); - } - - return actp; -} - -static bool call_chained_handler(struct sigaction *actp, int sig, - siginfo_t *siginfo, void *context) { - // Call the old signal handler - if (actp->sa_handler == SIG_DFL) { - // It's more reasonable to let jvm treat it as an unexpected exception - // instead of taking the default action. - return false; - } else if (actp->sa_handler != SIG_IGN) { - if ((actp->sa_flags & SA_NODEFER) == 0) { - // automaticlly block the signal - sigaddset(&(actp->sa_mask), sig); - } - - sa_handler_t hand; - sa_sigaction_t sa; - bool siginfo_flag_set = (actp->sa_flags & SA_SIGINFO) != 0; - // retrieve the chained handler - if (siginfo_flag_set) { - sa = actp->sa_sigaction; - } else { - hand = actp->sa_handler; - } - - if ((actp->sa_flags & SA_RESETHAND) != 0) { - actp->sa_handler = SIG_DFL; - } - - // try to honor the signal mask - sigset_t oset; - pthread_sigmask(SIG_SETMASK, &(actp->sa_mask), &oset); - - // call into the chained handler - if (siginfo_flag_set) { - (*sa)(sig, siginfo, context); - } else { - (*hand)(sig); - } - - // restore the signal mask - pthread_sigmask(SIG_SETMASK, &oset, 0); - } - // Tell jvm's signal handler the signal is taken care of. - return true; -} - -bool os::Solaris::chained_handler(int sig, siginfo_t* siginfo, void* context) { - bool chained = false; - // signal-chaining - if (UseSignalChaining) { - struct sigaction *actp = get_chained_signal_action(sig); - if (actp != NULL) { - chained = call_chained_handler(actp, sig, siginfo, context); - } - } - return chained; -} - -struct sigaction* os::Solaris::get_preinstalled_handler(int sig) { - assert((chainedsigactions != (struct sigaction *)NULL) && - (preinstalled_sigs != (int *)NULL), "signals not yet initialized"); - if (preinstalled_sigs[sig] != 0) { - return &chainedsigactions[sig]; - } - return NULL; -} - -void os::Solaris::save_preinstalled_handler(int sig, - struct sigaction& oldAct) { - assert(sig > 0 && sig <= Maxsignum, "vm signal out of expected range"); - assert((chainedsigactions != (struct sigaction *)NULL) && - (preinstalled_sigs != (int *)NULL), "signals not yet initialized"); - chainedsigactions[sig] = oldAct; - preinstalled_sigs[sig] = 1; -} - -void os::Solaris::set_signal_handler(int sig, bool set_installed, - bool oktochain) { - // Check for overwrite. - struct sigaction oldAct; - sigaction(sig, (struct sigaction*)NULL, &oldAct); - void* oldhand = - oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) - : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) && - oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) && - oldhand != CAST_FROM_FN_PTR(void*, signalHandler)) { - if (AllowUserSignalHandlers || !set_installed) { - // Do not overwrite; user takes responsibility to forward to us. - return; - } else if (UseSignalChaining) { - if (oktochain) { - // save the old handler in jvm - save_preinstalled_handler(sig, oldAct); - } else { - vm_exit_during_initialization("Signal chaining not allowed for VM interrupt signal."); - } - // libjsig also interposes the sigaction() call below and saves the - // old sigaction on it own. - } else { - fatal("Encountered unexpected pre-existing sigaction handler " - "%#lx for signal %d.", (long)oldhand, sig); - } - } - - struct sigaction sigAct; - sigfillset(&(sigAct.sa_mask)); - sigAct.sa_handler = SIG_DFL; - - sigAct.sa_sigaction = signalHandler; - // Handle SIGSEGV on alternate signal stack if - // not using stack banging - if (!UseStackBanging && sig == SIGSEGV) { - sigAct.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; - } else { - sigAct.sa_flags = SA_SIGINFO | SA_RESTART; - } - os::Solaris::set_our_sigflags(sig, sigAct.sa_flags); - - sigaction(sig, &sigAct, &oldAct); - - void* oldhand2 = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) - : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - assert(oldhand2 == oldhand, "no concurrent signal handler installation"); -} - - -#define DO_SIGNAL_CHECK(sig) \ - do { \ - if (!sigismember(&check_signal_done, sig)) { \ - os::Solaris::check_signal_handler(sig); \ - } \ - } while (0) - -// This method is a periodic task to check for misbehaving JNI applications -// under CheckJNI, we can add any periodic checks here - -void os::run_periodic_checks() { - // A big source of grief is hijacking virt. addr 0x0 on Solaris, - // thereby preventing a NULL checks. - if (!check_addr0_done) check_addr0_done = check_addr0(tty); - - if (check_signals == false) return; - - // SEGV and BUS if overridden could potentially prevent - // generation of hs*.log in the event of a crash, debugging - // such a case can be very challenging, so we absolutely - // check for the following for a good measure: - DO_SIGNAL_CHECK(SIGSEGV); - DO_SIGNAL_CHECK(SIGILL); - DO_SIGNAL_CHECK(SIGFPE); - DO_SIGNAL_CHECK(SIGBUS); - DO_SIGNAL_CHECK(SIGPIPE); - DO_SIGNAL_CHECK(SIGXFSZ); - DO_SIGNAL_CHECK(ASYNC_SIGNAL); - - // ReduceSignalUsage allows the user to override these handlers - // see comments at the very top and jvm_solaris.h - if (!ReduceSignalUsage) { - DO_SIGNAL_CHECK(SHUTDOWN1_SIGNAL); - DO_SIGNAL_CHECK(SHUTDOWN2_SIGNAL); - DO_SIGNAL_CHECK(SHUTDOWN3_SIGNAL); - DO_SIGNAL_CHECK(BREAK_SIGNAL); - } -} - -typedef int (*os_sigaction_t)(int, const struct sigaction *, struct sigaction *); - -static os_sigaction_t os_sigaction = NULL; - -void os::Solaris::check_signal_handler(int sig) { - char buf[O_BUFLEN]; - address jvmHandler = NULL; - - struct sigaction act; - if (os_sigaction == NULL) { - // only trust the default sigaction, in case it has been interposed - os_sigaction = (os_sigaction_t)dlsym(RTLD_DEFAULT, "sigaction"); - if (os_sigaction == NULL) return; - } - - os_sigaction(sig, (struct sigaction*)NULL, &act); - - address thisHandler = (act.sa_flags & SA_SIGINFO) - ? CAST_FROM_FN_PTR(address, act.sa_sigaction) - : CAST_FROM_FN_PTR(address, act.sa_handler); - - - switch (sig) { - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGPIPE: - case SIGXFSZ: - case SIGILL: - case ASYNC_SIGNAL: - jvmHandler = CAST_FROM_FN_PTR(address, signalHandler); - break; - - case SHUTDOWN1_SIGNAL: - case SHUTDOWN2_SIGNAL: - case SHUTDOWN3_SIGNAL: - case BREAK_SIGNAL: - jvmHandler = (address)user_handler(); - break; - - default: - return; - } - - if (thisHandler != jvmHandler) { - tty->print("Warning: %s handler ", exception_name(sig, buf, O_BUFLEN)); - tty->print("expected:%s", get_signal_handler_name(jvmHandler, buf, O_BUFLEN)); - tty->print_cr(" found:%s", get_signal_handler_name(thisHandler, buf, O_BUFLEN)); - // No need to check this sig any longer - sigaddset(&check_signal_done, sig); - // Running under non-interactive shell, SHUTDOWN2_SIGNAL will be reassigned SIG_IGN - if (sig == SHUTDOWN2_SIGNAL && !isatty(fileno(stdin))) { - tty->print_cr("Running in non-interactive shell, %s handler is replaced by shell", - exception_name(sig, buf, O_BUFLEN)); - } - } else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) { - tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN)); - tty->print("expected:"); - os::Posix::print_sa_flags(tty, os::Solaris::get_our_sigflags(sig)); - tty->cr(); - tty->print(" found:"); - os::Posix::print_sa_flags(tty, act.sa_flags); - tty->cr(); - // No need to check this sig any longer - sigaddset(&check_signal_done, sig); - } - - // Print all the signal handler state - if (sigismember(&check_signal_done, sig)) { - print_signal_handlers(tty, buf, O_BUFLEN); - } - -} - -void os::Solaris::install_signal_handlers() { - signal_handlers_are_installed = true; - - // signal-chaining - typedef void (*signal_setting_t)(); - signal_setting_t begin_signal_setting = NULL; - signal_setting_t end_signal_setting = NULL; - begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t, - dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting")); - if (begin_signal_setting != NULL) { - end_signal_setting = CAST_TO_FN_PTR(signal_setting_t, - dlsym(RTLD_DEFAULT, "JVM_end_signal_setting")); - get_signal_action = CAST_TO_FN_PTR(get_signal_t, - dlsym(RTLD_DEFAULT, "JVM_get_signal_action")); - libjsig_is_loaded = true; - assert(UseSignalChaining, "should enable signal-chaining"); - } - if (libjsig_is_loaded) { - // Tell libjsig jvm is setting signal handlers - (*begin_signal_setting)(); - } - - set_signal_handler(SIGSEGV, true, true); - set_signal_handler(SIGPIPE, true, true); - set_signal_handler(SIGXFSZ, true, true); - set_signal_handler(SIGBUS, true, true); - set_signal_handler(SIGILL, true, true); - set_signal_handler(SIGFPE, true, true); - set_signal_handler(ASYNC_SIGNAL, true, true); - - if (libjsig_is_loaded) { - // Tell libjsig jvm finishes setting signal handlers - (*end_signal_setting)(); - } - - // We don't activate signal checker if libjsig is in place, we trust ourselves - // and if UserSignalHandler is installed all bets are off. - // Log that signal checking is off only if -verbose:jni is specified. - if (CheckJNICalls) { - if (libjsig_is_loaded) { - log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled"); - check_signals = false; - } - if (AllowUserSignalHandlers) { - log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); - check_signals = false; - } - } -} - - -void report_error(const char* file_name, int line_no, const char* title, - const char* format, ...); - -// (Static) wrappers for the liblgrp API -os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home; -os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init; -os::Solaris::lgrp_fini_func_t os::Solaris::_lgrp_fini; -os::Solaris::lgrp_root_func_t os::Solaris::_lgrp_root; -os::Solaris::lgrp_children_func_t os::Solaris::_lgrp_children; -os::Solaris::lgrp_resources_func_t os::Solaris::_lgrp_resources; -os::Solaris::lgrp_nlgrps_func_t os::Solaris::_lgrp_nlgrps; -os::Solaris::lgrp_cookie_stale_func_t os::Solaris::_lgrp_cookie_stale; -os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0; - -static address resolve_symbol_lazy(const char* name) { - address addr = (address) dlsym(RTLD_DEFAULT, name); - if (addr == NULL) { - // RTLD_DEFAULT was not defined on some early versions of 2.5.1 - addr = (address) dlsym(RTLD_NEXT, name); - } - return addr; -} - -static address resolve_symbol(const char* name) { - address addr = resolve_symbol_lazy(name); - if (addr == NULL) { - fatal(dlerror()); - } - return addr; -} - -void os::Solaris::libthread_init() { - address func = (address)dlsym(RTLD_DEFAULT, "_thr_suspend_allmutators"); - - lwp_priocntl_init(); - - // RTLD_DEFAULT was not defined on some early versions of 5.5.1 - if (func == NULL) { - func = (address) dlsym(RTLD_NEXT, "_thr_suspend_allmutators"); - // Guarantee that this VM is running on an new enough OS (5.6 or - // later) that it will have a new enough libthread.so. - guarantee(func != NULL, "libthread.so is too old."); - } - - int size; - void (*handler_info_func)(address *, int *); - handler_info_func = CAST_TO_FN_PTR(void (*)(address *, int *), resolve_symbol("thr_sighndlrinfo")); - handler_info_func(&handler_start, &size); - handler_end = handler_start + size; -} - - -int_fnP_mutex_tP os::Solaris::_mutex_lock; -int_fnP_mutex_tP os::Solaris::_mutex_trylock; -int_fnP_mutex_tP os::Solaris::_mutex_unlock; -int_fnP_mutex_tP_i_vP os::Solaris::_mutex_init; -int_fnP_mutex_tP os::Solaris::_mutex_destroy; -int os::Solaris::_mutex_scope = USYNC_THREAD; - -int_fnP_cond_tP_mutex_tP_timestruc_tP os::Solaris::_cond_timedwait; -int_fnP_cond_tP_mutex_tP os::Solaris::_cond_wait; -int_fnP_cond_tP os::Solaris::_cond_signal; -int_fnP_cond_tP os::Solaris::_cond_broadcast; -int_fnP_cond_tP_i_vP os::Solaris::_cond_init; -int_fnP_cond_tP os::Solaris::_cond_destroy; -int os::Solaris::_cond_scope = USYNC_THREAD; -bool os::Solaris::_synchronization_initialized; - -void os::Solaris::synchronization_init() { - if (UseLWPSynchronization) { - os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_lock"))); - os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_trylock"))); - os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_unlock"))); - os::Solaris::set_mutex_init(lwp_mutex_init); - os::Solaris::set_mutex_destroy(lwp_mutex_destroy); - os::Solaris::set_mutex_scope(USYNC_THREAD); - - os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("_lwp_cond_timedwait"))); - os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("_lwp_cond_wait"))); - os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("_lwp_cond_signal"))); - os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("_lwp_cond_broadcast"))); - os::Solaris::set_cond_init(lwp_cond_init); - os::Solaris::set_cond_destroy(lwp_cond_destroy); - os::Solaris::set_cond_scope(USYNC_THREAD); - } else { - os::Solaris::set_mutex_scope(USYNC_THREAD); - os::Solaris::set_cond_scope(USYNC_THREAD); - - if (UsePthreads) { - os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_lock"))); - os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_trylock"))); - os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_unlock"))); - os::Solaris::set_mutex_init(pthread_mutex_default_init); - os::Solaris::set_mutex_destroy(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_destroy"))); - - os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("pthread_cond_timedwait"))); - os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("pthread_cond_wait"))); - os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_signal"))); - os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_broadcast"))); - os::Solaris::set_cond_init(pthread_cond_default_init); - os::Solaris::set_cond_destroy(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_destroy"))); - } else { - os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_lock"))); - os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_trylock"))); - os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_unlock"))); - os::Solaris::set_mutex_init(::mutex_init); - os::Solaris::set_mutex_destroy(::mutex_destroy); - - os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("cond_timedwait"))); - os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("cond_wait"))); - os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("cond_signal"))); - os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("cond_broadcast"))); - os::Solaris::set_cond_init(::cond_init); - os::Solaris::set_cond_destroy(::cond_destroy); - } - } - _synchronization_initialized = true; -} - -bool os::Solaris::liblgrp_init() { - void *handle = dlopen("liblgrp.so.1", RTLD_LAZY); - if (handle != NULL) { - os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home"))); - os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init"))); - os::Solaris::set_lgrp_fini(CAST_TO_FN_PTR(lgrp_fini_func_t, dlsym(handle, "lgrp_fini"))); - os::Solaris::set_lgrp_root(CAST_TO_FN_PTR(lgrp_root_func_t, dlsym(handle, "lgrp_root"))); - os::Solaris::set_lgrp_children(CAST_TO_FN_PTR(lgrp_children_func_t, dlsym(handle, "lgrp_children"))); - os::Solaris::set_lgrp_resources(CAST_TO_FN_PTR(lgrp_resources_func_t, dlsym(handle, "lgrp_resources"))); - os::Solaris::set_lgrp_nlgrps(CAST_TO_FN_PTR(lgrp_nlgrps_func_t, dlsym(handle, "lgrp_nlgrps"))); - os::Solaris::set_lgrp_cookie_stale(CAST_TO_FN_PTR(lgrp_cookie_stale_func_t, - dlsym(handle, "lgrp_cookie_stale"))); - - lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER); - set_lgrp_cookie(c); - return true; - } - return false; -} - -// int pset_getloadavg(psetid_t pset, double loadavg[], int nelem); -typedef long (*pset_getloadavg_type)(psetid_t pset, double loadavg[], int nelem); -static pset_getloadavg_type pset_getloadavg_ptr = NULL; - -void init_pset_getloadavg_ptr(void) { - pset_getloadavg_ptr = - (pset_getloadavg_type)dlsym(RTLD_DEFAULT, "pset_getloadavg"); - if (pset_getloadavg_ptr == NULL) { - log_warning(os)("pset_getloadavg function not found"); - } -} - -int os::Solaris::_dev_zero_fd = -1; - -// this is called _before_ the global arguments have been parsed -void os::init(void) { - _initial_pid = getpid(); - - max_hrtime = first_hrtime = gethrtime(); - - init_random(1234567); - - page_size = sysconf(_SC_PAGESIZE); - if (page_size == -1) { - fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno)); - } - init_page_sizes((size_t) page_size); - - Solaris::initialize_system_info(); - - int fd = ::open("/dev/zero", O_RDWR); - if (fd < 0) { - fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno)); - } else { - Solaris::set_dev_zero_fd(fd); - - // Close on exec, child won't inherit. - fcntl(fd, F_SETFD, FD_CLOEXEC); - } - - clock_tics_per_sec = CLK_TCK; - - // check if dladdr1() exists; dladdr1 can provide more information than - // dladdr for os::dll_address_to_function_name. It comes with SunOS 5.9 - // and is available on linker patches for 5.7 and 5.8. - // libdl.so must have been loaded, this call is just an entry lookup - void * hdl = dlopen("libdl.so", RTLD_NOW); - if (hdl) { - dladdr1_func = CAST_TO_FN_PTR(dladdr1_func_type, dlsym(hdl, "dladdr1")); - } - - // main_thread points to the thread that created/loaded the JVM. - main_thread = thr_self(); - - // dynamic lookup of functions that may not be available in our lowest - // supported Solaris release - void * handle = dlopen("libc.so.1", RTLD_LAZY); - if (handle != NULL) { - Solaris::_pthread_setname_np = // from 11.3 - (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np"); - } - - // Shared Posix initialization - os::Posix::init(); -} - -// To install functions for atexit system call -extern "C" { - static void perfMemory_exit_helper() { - perfMemory_exit(); - } -} - -// this is called _after_ the global arguments have been parsed -jint os::init_2(void) { - // try to enable extended file IO ASAP, see 6431278 - os::Solaris::try_enable_extended_io(); - - // Check and sets minimum stack sizes against command line options - if (Posix::set_minimum_stack_sizes() == JNI_ERR) { - return JNI_ERR; - } - - Solaris::libthread_init(); - - if (UseNUMA) { - if (!Solaris::liblgrp_init()) { - FLAG_SET_ERGO(UseNUMA, false); - } else { - size_t lgrp_limit = os::numa_get_groups_num(); - int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtInternal); - size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit); - FREE_C_HEAP_ARRAY(int, lgrp_ids); - if (lgrp_num < 2) { - // There's only one locality group, disable NUMA unless - // user explicilty forces NUMA optimizations on single-node/UMA systems - UseNUMA = ForceNUMA; - } - } - } - - // When NUMA requested, not-NUMA-aware allocations default to interleaving. - if (UseNUMA && !UseNUMAInterleaving) { - FLAG_SET_ERGO_IF_DEFAULT(UseNUMAInterleaving, true); - } - - Solaris::signal_sets_init(); - Solaris::init_signal_mem(); - Solaris::install_signal_handlers(); - // Initialize data for jdk.internal.misc.Signal - if (!ReduceSignalUsage) { - jdk_misc_signal_init(); - } - - // initialize synchronization primitives to use either thread or - // lwp synchronization (controlled by UseLWPSynchronization) - Solaris::synchronization_init(); - DEBUG_ONLY(os::set_mutex_init_done();) - - if (MaxFDLimit) { - // set the number of file descriptors to max. print out error - // if getrlimit/setrlimit fails but continue regardless. - struct rlimit nbr_files; - int status = getrlimit(RLIMIT_NOFILE, &nbr_files); - if (status != 0) { - log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); - } else { - nbr_files.rlim_cur = nbr_files.rlim_max; - status = setrlimit(RLIMIT_NOFILE, &nbr_files); - if (status != 0) { - log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); - } - } - } - - // Calculate theoretical max. size of Threads to guard gainst - // artifical out-of-memory situations, where all available address- - // space has been reserved by thread stacks. Default stack size is 1Mb. - size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ? - JavaThread::stack_size_at_create() : (1*K*K); - assert(pre_thread_stack_size != 0, "Must have a stack"); - // Solaris has a maximum of 4Gb of user programs. Calculate the thread limit when - // we should start doing Virtual Memory banging. Currently when the threads will - // have used all but 200Mb of space. - size_t max_address_space = ((unsigned int)4 * K * K * K) - (200 * K * K); - Solaris::_os_thread_limit = max_address_space / pre_thread_stack_size; - - // at-exit methods are called in the reverse order of their registration. - // In Solaris 7 and earlier, atexit functions are called on return from - // main or as a result of a call to exit(3C). There can be only 32 of - // these functions registered and atexit() does not set errno. In Solaris - // 8 and later, there is no limit to the number of functions registered - // and atexit() sets errno. In addition, in Solaris 8 and later, atexit - // functions are called upon dlclose(3DL) in addition to return from main - // and exit(3C). - - if (PerfAllowAtExitRegistration) { - // only register atexit functions if PerfAllowAtExitRegistration is set. - // atexit functions can be delayed until process exit time, which - // can be problematic for embedded VM situations. Embedded VMs should - // call DestroyJavaVM() to assure that VM resources are released. - - // note: perfMemory_exit_helper atexit function may be removed in - // the future if the appropriate cleanup code can be added to the - // VM_Exit VMOperation's doit method. - if (atexit(perfMemory_exit_helper) != 0) { - warning("os::init2 atexit(perfMemory_exit_helper) failed"); - } - } - - // Init pset_loadavg function pointer - init_pset_getloadavg_ptr(); - - // Shared Posix initialization - os::Posix::init_2(); - - return JNI_OK; -} - -// Is a (classpath) directory empty? -bool os::dir_is_empty(const char* path) { - DIR *dir = NULL; - struct dirent *ptr; - - dir = opendir(path); - if (dir == NULL) return true; - - // Scan the directory - bool result = true; - while (result && (ptr = readdir(dir)) != NULL) { - if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) { - result = false; - } - } - closedir(dir); - return result; -} - -// This code originates from JDK's sysOpen and open64_w -// from src/solaris/hpi/src/system_md.c - -int os::open(const char *path, int oflag, int mode) { - if (strlen(path) > MAX_PATH - 1) { - errno = ENAMETOOLONG; - return -1; - } - int fd; - - fd = ::open64(path, oflag, mode); - if (fd == -1) return -1; - - // If the open succeeded, the file might still be a directory - { - struct stat64 buf64; - int ret = ::fstat64(fd, &buf64); - int st_mode = buf64.st_mode; - - if (ret != -1) { - if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; - ::close(fd); - return -1; - } - } else { - ::close(fd); - return -1; - } - } - - // 32-bit Solaris systems suffer from: - // - // - an historical default soft limit of 256 per-process file - // descriptors that is too low for many Java programs. - // - // - a design flaw where file descriptors created using stdio - // fopen must be less than 256, _even_ when the first limit above - // has been raised. This can cause calls to fopen (but not calls to - // open, for example) to fail mysteriously, perhaps in 3rd party - // native code (although the JDK itself uses fopen). One can hardly - // criticize them for using this most standard of all functions. - // - // We attempt to make everything work anyways by: - // - // - raising the soft limit on per-process file descriptors beyond - // 256 - // - // - As of Solaris 10u4, we can request that Solaris raise the 256 - // stdio fopen limit by calling function enable_extended_FILE_stdio. - // This is done in init_2 and recorded in enabled_extended_FILE_stdio - // - // - If we are stuck on an old (pre 10u4) Solaris system, we can - // workaround the bug by remapping non-stdio file descriptors below - // 256 to ones beyond 256, which is done below. - // - // See: - // 1085341: 32-bit stdio routines should support file descriptors >255 - // 6533291: Work around 32-bit Solaris stdio limit of 256 open files - // 6431278: Netbeans crash on 32 bit Solaris: need to call - // enable_extended_FILE_stdio() in VM initialisation - // Giri Mandalika's blog - // http://technopark02.blogspot.com/2005_05_01_archive.html - // -#ifndef _LP64 - if ((!enabled_extended_FILE_stdio) && fd < 256) { - int newfd = ::fcntl(fd, F_DUPFD, 256); - if (newfd != -1) { - ::close(fd); - fd = newfd; - } - } -#endif // 32-bit Solaris - - // All file descriptors that are opened in the JVM and not - // specifically destined for a subprocess should have the - // close-on-exec flag set. If we don't set it, then careless 3rd - // party native code might fork and exec without closing all - // appropriate file descriptors (e.g. as we do in closeDescriptors in - // UNIXProcess.c), and this in turn might: - // - // - cause end-of-file to fail to be detected on some file - // descriptors, resulting in mysterious hangs, or - // - // - might cause an fopen in the subprocess to fail on a system - // suffering from bug 1085341. - // - // (Yes, the default setting of the close-on-exec flag is a Unix - // design flaw) - // - // See: - // 1085341: 32-bit stdio routines should support file descriptors >255 - // 4843136: (process) pipe file descriptor from Runtime.exec not being closed - // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 - // -#ifdef FD_CLOEXEC - { - int flags = ::fcntl(fd, F_GETFD); - if (flags != -1) { - ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC); - } - } -#endif - - return fd; -} - -// create binary file, rewriting existing file if required -int os::create_binary_file(const char* path, bool rewrite_existing) { - int oflags = O_WRONLY | O_CREAT; - if (!rewrite_existing) { - oflags |= O_EXCL; - } - return ::open64(path, oflags, S_IREAD | S_IWRITE); -} - -// return current position of file pointer -jlong os::current_file_offset(int fd) { - return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); -} - -// move file pointer to the specified offset -jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); -} - -jlong os::lseek(int fd, jlong offset, int whence) { - return (jlong) ::lseek64(fd, offset, whence); -} - -int os::ftruncate(int fd, jlong length) { - return ::ftruncate64(fd, length); -} - -int os::fsync(int fd) { - RESTARTABLE_RETURN_INT(::fsync(fd)); -} - -int os::available(int fd, jlong *bytes) { - assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, - "Assumed _thread_in_native"); - jlong cur, end; - int mode; - struct stat64 buf64; - - if (::fstat64(fd, &buf64) >= 0) { - mode = buf64.st_mode; - if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { - int n,ioctl_return; - - RESTARTABLE(::ioctl(fd, FIONREAD, &n), ioctl_return); - if (ioctl_return>= 0) { - *bytes = n; - return 1; - } - } - } - if ((cur = ::lseek64(fd, 0L, SEEK_CUR)) == -1) { - return 0; - } else if ((end = ::lseek64(fd, 0L, SEEK_END)) == -1) { - return 0; - } else if (::lseek64(fd, cur, SEEK_SET) == -1) { - return 0; - } - *bytes = end - cur; - return 1; -} - -// Map a block of memory. -char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, bool read_only, - bool allow_exec) { - int prot; - int flags; - - if (read_only) { - prot = PROT_READ; - flags = MAP_SHARED; - } else { - prot = PROT_READ | PROT_WRITE; - flags = MAP_PRIVATE; - } - - if (allow_exec) { - prot |= PROT_EXEC; - } - - if (addr != NULL) { - flags |= MAP_FIXED; - } - - char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags, - fd, file_offset); - if (mapped_address == MAP_FAILED) { - return NULL; - } - return mapped_address; -} - - -// Remap a block of memory. -char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset, - char *addr, size_t bytes, bool read_only, - bool allow_exec) { - // same as map_memory() on this OS - return os::map_memory(fd, file_name, file_offset, addr, bytes, read_only, - allow_exec); -} - - -// Unmap a block of memory. -bool os::pd_unmap_memory(char* addr, size_t bytes) { - return munmap(addr, bytes) == 0; -} - -void os::pause() { - char filename[MAX_PATH]; - if (PauseAtStartupFile && PauseAtStartupFile[0]) { - jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile); - } else { - jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id()); - } - - int fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666); - if (fd != -1) { - struct stat buf; - ::close(fd); - while (::stat(filename, &buf) == 0) { - (void)::poll(NULL, 0, 100); - } - } else { - jio_fprintf(stderr, - "Could not open pause file '%s', continuing immediately.\n", filename); - } -} - -#ifndef PRODUCT -#ifdef INTERPOSE_ON_SYSTEM_SYNCH_FUNCTIONS -// Turn this on if you need to trace synch operations. -// Set RECORD_SYNCH_LIMIT to a large-enough value, -// and call record_synch_enable and record_synch_disable -// around the computation of interest. - -void record_synch(char* name, bool returning); // defined below - -class RecordSynch { - char* _name; - public: - RecordSynch(char* name) :_name(name) { record_synch(_name, false); } - ~RecordSynch() { record_synch(_name, true); } -}; - -#define CHECK_SYNCH_OP(ret, name, params, args, inner) \ -extern "C" ret name params { \ - typedef ret name##_t params; \ - static name##_t* implem = NULL; \ - static int callcount = 0; \ - if (implem == NULL) { \ - implem = (name##_t*) dlsym(RTLD_NEXT, #name); \ - if (implem == NULL) fatal(dlerror()); \ - } \ - ++callcount; \ - RecordSynch _rs(#name); \ - inner; \ - return implem args; \ -} -// in dbx, examine callcounts this way: -// for n in $(eval whereis callcount | awk '{print $2}'); do print $n; done - -#define CHECK_POINTER_OK(p) \ - (!Universe::is_fully_initialized() || !Universe::is_reserved_heap((oop)(p))) -#define CHECK_MU \ - if (!CHECK_POINTER_OK(mu)) fatal("Mutex must be in C heap only."); -#define CHECK_CV \ - if (!CHECK_POINTER_OK(cv)) fatal("Condvar must be in C heap only."); -#define CHECK_P(p) \ - if (!CHECK_POINTER_OK(p)) fatal(false, "Pointer must be in C heap only."); - -#define CHECK_MUTEX(mutex_op) \ - CHECK_SYNCH_OP(int, mutex_op, (mutex_t *mu), (mu), CHECK_MU); - -CHECK_MUTEX( mutex_lock) -CHECK_MUTEX( _mutex_lock) -CHECK_MUTEX( mutex_unlock) -CHECK_MUTEX(_mutex_unlock) -CHECK_MUTEX( mutex_trylock) -CHECK_MUTEX(_mutex_trylock) - -#define CHECK_COND(cond_op) \ - CHECK_SYNCH_OP(int, cond_op, (cond_t *cv, mutex_t *mu), (cv, mu), CHECK_MU; CHECK_CV); - -CHECK_COND( cond_wait); -CHECK_COND(_cond_wait); -CHECK_COND(_cond_wait_cancel); - -#define CHECK_COND2(cond_op) \ - CHECK_SYNCH_OP(int, cond_op, (cond_t *cv, mutex_t *mu, timestruc_t* ts), (cv, mu, ts), CHECK_MU; CHECK_CV); - -CHECK_COND2( cond_timedwait); -CHECK_COND2(_cond_timedwait); -CHECK_COND2(_cond_timedwait_cancel); - -// do the _lwp_* versions too -#define mutex_t lwp_mutex_t -#define cond_t lwp_cond_t -CHECK_MUTEX( _lwp_mutex_lock) -CHECK_MUTEX( _lwp_mutex_unlock) -CHECK_MUTEX( _lwp_mutex_trylock) -CHECK_MUTEX( __lwp_mutex_lock) -CHECK_MUTEX( __lwp_mutex_unlock) -CHECK_MUTEX( __lwp_mutex_trylock) -CHECK_MUTEX(___lwp_mutex_lock) -CHECK_MUTEX(___lwp_mutex_unlock) - -CHECK_COND( _lwp_cond_wait); -CHECK_COND( __lwp_cond_wait); -CHECK_COND(___lwp_cond_wait); - -CHECK_COND2( _lwp_cond_timedwait); -CHECK_COND2( __lwp_cond_timedwait); -#undef mutex_t -#undef cond_t - -CHECK_SYNCH_OP(int, _lwp_suspend2, (int lwp, int *n), (lwp, n), 0); -CHECK_SYNCH_OP(int,__lwp_suspend2, (int lwp, int *n), (lwp, n), 0); -CHECK_SYNCH_OP(int, _lwp_kill, (int lwp, int n), (lwp, n), 0); -CHECK_SYNCH_OP(int,__lwp_kill, (int lwp, int n), (lwp, n), 0); -CHECK_SYNCH_OP(int, _lwp_sema_wait, (lwp_sema_t* p), (p), CHECK_P(p)); -CHECK_SYNCH_OP(int,__lwp_sema_wait, (lwp_sema_t* p), (p), CHECK_P(p)); -CHECK_SYNCH_OP(int, _lwp_cond_broadcast, (lwp_cond_t* cv), (cv), CHECK_CV); -CHECK_SYNCH_OP(int,__lwp_cond_broadcast, (lwp_cond_t* cv), (cv), CHECK_CV); - - -// recording machinery: - -enum { RECORD_SYNCH_LIMIT = 200 }; -char* record_synch_name[RECORD_SYNCH_LIMIT]; -void* record_synch_arg0ptr[RECORD_SYNCH_LIMIT]; -bool record_synch_returning[RECORD_SYNCH_LIMIT]; -thread_t record_synch_thread[RECORD_SYNCH_LIMIT]; -int record_synch_count = 0; -bool record_synch_enabled = false; - -// in dbx, examine recorded data this way: -// for n in name arg0ptr returning thread; do print record_synch_$n[0..record_synch_count-1]; done - -void record_synch(char* name, bool returning) { - if (record_synch_enabled) { - if (record_synch_count < RECORD_SYNCH_LIMIT) { - record_synch_name[record_synch_count] = name; - record_synch_returning[record_synch_count] = returning; - record_synch_thread[record_synch_count] = thr_self(); - record_synch_arg0ptr[record_synch_count] = &name; - record_synch_count++; - } - // put more checking code here: - // ... - } -} - -void record_synch_enable() { - // start collecting trace data, if not already doing so - if (!record_synch_enabled) record_synch_count = 0; - record_synch_enabled = true; -} - -void record_synch_disable() { - // stop collecting trace data - record_synch_enabled = false; -} - -#endif // INTERPOSE_ON_SYSTEM_SYNCH_FUNCTIONS -#endif // PRODUCT - -const intptr_t thr_time_off = (intptr_t)(&((prusage_t *)(NULL))->pr_utime); -const intptr_t thr_time_size = (intptr_t)(&((prusage_t *)(NULL))->pr_ttime) - - (intptr_t)(&((prusage_t *)(NULL))->pr_utime); - - -// JVMTI & JVM monitoring and management support -// The thread_cpu_time() and current_thread_cpu_time() are only -// supported if is_thread_cpu_time_supported() returns true. -// They are not supported on Solaris T1. - -// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) -// are used by JVM M&M and JVMTI to get user+sys or user CPU time -// of a thread. -// -// current_thread_cpu_time() and thread_cpu_time(Thread *) -// returns the fast estimate available on the platform. - -// hrtime_t gethrvtime() return value includes -// user time but does not include system time -jlong os::current_thread_cpu_time() { - return (jlong) gethrvtime(); -} - -jlong os::thread_cpu_time(Thread *thread) { - // return user level CPU time only to be consistent with - // what current_thread_cpu_time returns. - // thread_cpu_time_info() must be changed if this changes - return os::thread_cpu_time(thread, false /* user time only */); -} - -jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { - if (user_sys_cpu_time) { - return os::thread_cpu_time(Thread::current(), user_sys_cpu_time); - } else { - return os::current_thread_cpu_time(); - } -} - -jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { - char proc_name[64]; - int count; - prusage_t prusage; - jlong lwp_time; - int fd; - - sprintf(proc_name, "/proc/%d/lwp/%d/lwpusage", - getpid(), - thread->osthread()->lwp_id()); - fd = ::open(proc_name, O_RDONLY); - if (fd == -1) return -1; - - do { - count = ::pread(fd, - (void *)&prusage.pr_utime, - thr_time_size, - thr_time_off); - } while (count < 0 && errno == EINTR); - ::close(fd); - if (count < 0) return -1; - - if (user_sys_cpu_time) { - // user + system CPU time - lwp_time = (((jlong)prusage.pr_stime.tv_sec + - (jlong)prusage.pr_utime.tv_sec) * (jlong)1000000000) + - (jlong)prusage.pr_stime.tv_nsec + - (jlong)prusage.pr_utime.tv_nsec; - } else { - // user level CPU time only - lwp_time = ((jlong)prusage.pr_utime.tv_sec * (jlong)1000000000) + - (jlong)prusage.pr_utime.tv_nsec; - } - - return (lwp_time); -} - -void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits - info_ptr->may_skip_backward = false; // elapsed time not wall time - info_ptr->may_skip_forward = false; // elapsed time not wall time - info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned -} - -void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits - info_ptr->may_skip_backward = false; // elapsed time not wall time - info_ptr->may_skip_forward = false; // elapsed time not wall time - info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned -} - -bool os::is_thread_cpu_time_supported() { - return true; -} - -// System loadavg support. Returns -1 if load average cannot be obtained. -// Return the load average for our processor set if the primitive exists -// (Solaris 9 and later). Otherwise just return system wide loadavg. -int os::loadavg(double loadavg[], int nelem) { - if (pset_getloadavg_ptr != NULL) { - return (*pset_getloadavg_ptr)(PS_MYID, loadavg, nelem); - } else { - return ::getloadavg(loadavg, nelem); - } -} - -//--------------------------------------------------------------------------------- - -bool os::find(address addr, outputStream* st) { - Dl_info dlinfo; - memset(&dlinfo, 0, sizeof(dlinfo)); - if (dladdr(addr, &dlinfo) != 0) { - st->print(PTR_FORMAT ": ", addr); - if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) { - st->print("%s+%#lx", dlinfo.dli_sname, addr-(intptr_t)dlinfo.dli_saddr); - } else if (dlinfo.dli_fbase != NULL) { - st->print("", addr-(intptr_t)dlinfo.dli_fbase); - } else { - st->print(""); - } - if (dlinfo.dli_fname != NULL) { - st->print(" in %s", dlinfo.dli_fname); - } - if (dlinfo.dli_fbase != NULL) { - st->print(" at " PTR_FORMAT, dlinfo.dli_fbase); - } - st->cr(); - - if (Verbose) { - // decode some bytes around the PC - address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size()); - address end = clamp_address_in_page(addr+40, addr, os::vm_page_size()); - address lowest = (address) dlinfo.dli_sname; - if (!lowest) lowest = (address) dlinfo.dli_fbase; - if (begin < lowest) begin = lowest; - Dl_info dlinfo2; - if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr - && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) { - end = (address) dlinfo2.dli_saddr; - } - Disassembler::decode(begin, end, st); - } - return true; - } - return false; -} - -// Following function has been added to support HotSparc's libjvm.so running -// under Solaris production JDK 1.2.2 / 1.3.0. These came from -// src/solaris/hpi/native_threads in the EVM codebase. -// -// NOTE: This is no longer needed in the 1.3.1 and 1.4 production release -// libraries and should thus be removed. We will leave it behind for a while -// until we no longer want to able to run on top of 1.3.0 Solaris production -// JDK. See 4341971. - -#define STACK_SLACK 0x800 - -extern "C" { - intptr_t sysThreadAvailableStackWithSlack() { - stack_t st; - intptr_t retval, stack_top; - retval = thr_stksegment(&st); - assert(retval == 0, "incorrect return value from thr_stksegment"); - assert((address)&st < (address)st.ss_sp, "Invalid stack base returned"); - assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned"); - stack_top=(intptr_t)st.ss_sp-st.ss_size; - return ((intptr_t)&stack_top - stack_top - STACK_SLACK); - } -} - -// ObjectMonitor park-unpark infrastructure ... -// -// We implement Solaris and Linux PlatformEvents with the -// obvious condvar-mutex-flag triple. -// Another alternative that works quite well is pipes: -// Each PlatformEvent consists of a pipe-pair. -// The thread associated with the PlatformEvent -// calls park(), which reads from the input end of the pipe. -// Unpark() writes into the other end of the pipe. -// The write-side of the pipe must be set NDELAY. -// Unfortunately pipes consume a large # of handles. -// Native solaris lwp_park() and lwp_unpark() work nicely, too. -// Using pipes for the 1st few threads might be workable, however. -// -// park() is permitted to return spuriously. -// Callers of park() should wrap the call to park() in -// an appropriate loop. A litmus test for the correct -// usage of park is the following: if park() were modified -// to immediately return 0 your code should still work, -// albeit degenerating to a spin loop. -// -// In a sense, park()-unpark() just provides more polite spinning -// and polling with the key difference over naive spinning being -// that a parked thread needs to be explicitly unparked() in order -// to wake up and to poll the underlying condition. -// -// Assumption: -// Only one parker can exist on an event, which is why we allocate -// them per-thread. Multiple unparkers can coexist. -// -// _Event transitions in park() -// -1 => -1 : illegal -// 1 => 0 : pass - return immediately -// 0 => -1 : block; then set _Event to 0 before returning -// -// _Event transitions in unpark() -// 0 => 1 : just return -// 1 => 1 : just return -// -1 => either 0 or 1; must signal target thread -// That is, we can safely transition _Event from -1 to either -// 0 or 1. -// -// _Event serves as a restricted-range semaphore. -// -1 : thread is blocked, i.e. there is a waiter -// 0 : neutral: thread is running or ready, -// could have been signaled after a wait started -// 1 : signaled - thread is running or ready -// -// Another possible encoding of _Event would be with -// explicit "PARKED" == 01b and "SIGNALED" == 10b bits. -// -// TODO-FIXME: add DTRACE probes for: -// 1. Tx parks -// 2. Ty unparks Tx -// 3. Tx resumes from park - - -// value determined through experimentation -#define ROUNDINGFIX 11 - -// utility to compute the abstime argument to timedwait. -// TODO-FIXME: switch from compute_abstime() to unpackTime(). - -static timestruc_t* compute_abstime(timestruc_t* abstime, jlong millis) { - // millis is the relative timeout time - // abstime will be the absolute timeout time - if (millis < 0) millis = 0; - struct timeval now; - int status = gettimeofday(&now, NULL); - assert(status == 0, "gettimeofday"); - jlong seconds = millis / 1000; - jlong max_wait_period; - - if (UseLWPSynchronization) { - // forward port of fix for 4275818 (not sleeping long enough) - // There was a bug in Solaris 6, 7 and pre-patch 5 of 8 where - // _lwp_cond_timedwait() used a round_down algorithm rather - // than a round_up. For millis less than our roundfactor - // it rounded down to 0 which doesn't meet the spec. - // For millis > roundfactor we may return a bit sooner, but - // since we can not accurately identify the patch level and - // this has already been fixed in Solaris 9 and 8 we will - // leave it alone rather than always rounding down. - - if (millis > 0 && millis < ROUNDINGFIX) millis = ROUNDINGFIX; - // It appears that when we go directly through Solaris _lwp_cond_timedwait() - // the acceptable max time threshold is smaller than for libthread on 2.5.1 and 2.6 - max_wait_period = 21000000; - } else { - max_wait_period = 50000000; - } - millis %= 1000; - if (seconds > max_wait_period) { // see man cond_timedwait(3T) - seconds = max_wait_period; - } - abstime->tv_sec = now.tv_sec + seconds; - long usec = now.tv_usec + millis * 1000; - if (usec >= 1000000) { - abstime->tv_sec += 1; - usec -= 1000000; - } - abstime->tv_nsec = usec * 1000; - return abstime; -} - -void os::PlatformEvent::park() { // AKA: down() - // Transitions for _Event: - // -1 => -1 : illegal - // 1 => 0 : pass - return immediately - // 0 => -1 : block; then set _Event to 0 before returning - - // Invariant: Only the thread associated with the Event/PlatformEvent - // may call park(). - assert(_nParked == 0, "invariant"); - - int v; - for (;;) { - v = _Event; - if (Atomic::cmpxchg(&_Event, v, v-1) == v) break; - } - guarantee(v >= 0, "invariant"); - if (v == 0) { - // Do this the hard way by blocking ... - // See http://monaco.sfbay/detail.jsf?cr=5094058. - int status = os::Solaris::mutex_lock(_mutex); - assert_status(status == 0, status, "mutex_lock"); - guarantee(_nParked == 0, "invariant"); - ++_nParked; - while (_Event < 0) { - // for some reason, under 2.7 lwp_cond_wait() may return ETIME ... - // Treat this the same as if the wait was interrupted - // With usr/lib/lwp going to kernel, always handle ETIME - status = os::Solaris::cond_wait(_cond, _mutex); - if (status == ETIME) status = EINTR; - assert_status(status == 0 || status == EINTR, status, "cond_wait"); - } - --_nParked; - _Event = 0; - status = os::Solaris::mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - // Paranoia to ensure our locked and lock-free paths interact - // correctly with each other. - OrderAccess::fence(); - } -} - -int os::PlatformEvent::park(jlong millis) { - // Transitions for _Event: - // -1 => -1 : illegal - // 1 => 0 : pass - return immediately - // 0 => -1 : block; then set _Event to 0 before returning - - guarantee(_nParked == 0, "invariant"); - int v; - for (;;) { - v = _Event; - if (Atomic::cmpxchg(&_Event, v, v-1) == v) break; - } - guarantee(v >= 0, "invariant"); - if (v != 0) return OS_OK; - - int ret = OS_TIMEOUT; - timestruc_t abst; - compute_abstime(&abst, millis); - - // See http://monaco.sfbay/detail.jsf?cr=5094058. - int status = os::Solaris::mutex_lock(_mutex); - assert_status(status == 0, status, "mutex_lock"); - guarantee(_nParked == 0, "invariant"); - ++_nParked; - while (_Event < 0) { - int status = os::Solaris::cond_timedwait(_cond, _mutex, &abst); - assert_status(status == 0 || status == EINTR || - status == ETIME || status == ETIMEDOUT, - status, "cond_timedwait"); - if (!FilterSpuriousWakeups) break; // previous semantics - if (status == ETIME || status == ETIMEDOUT) break; - // We consume and ignore EINTR and spurious wakeups. - } - --_nParked; - if (_Event >= 0) ret = OS_OK; - _Event = 0; - status = os::Solaris::mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - // Paranoia to ensure our locked and lock-free paths interact - // correctly with each other. - OrderAccess::fence(); - return ret; -} - -void os::PlatformEvent::unpark() { - // Transitions for _Event: - // 0 => 1 : just return - // 1 => 1 : just return - // -1 => either 0 or 1; must signal target thread - // That is, we can safely transition _Event from -1 to either - // 0 or 1. - // See also: "Semaphores in Plan 9" by Mullender & Cox - // - // Note: Forcing a transition from "-1" to "1" on an unpark() means - // that it will take two back-to-back park() calls for the owning - // thread to block. This has the benefit of forcing a spurious return - // from the first park() call after an unpark() call which will help - // shake out uses of park() and unpark() without condition variables. - - if (Atomic::xchg(&_Event, 1) >= 0) return; - - // If the thread associated with the event was parked, wake it. - // Wait for the thread assoc with the PlatformEvent to vacate. - int status = os::Solaris::mutex_lock(_mutex); - assert_status(status == 0, status, "mutex_lock"); - int AnyWaiters = _nParked; - status = os::Solaris::mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant"); - if (AnyWaiters != 0) { - // Note that we signal() *after* dropping the lock for "immortal" Events. - // This is safe and avoids a common class of futile wakeups. In rare - // circumstances this can cause a thread to return prematurely from - // cond_{timed}wait() but the spurious wakeup is benign and the victim - // will simply re-test the condition and re-park itself. - // This provides particular benefit if the underlying platform does not - // provide wait morphing. - status = os::Solaris::cond_signal(_cond); - assert_status(status == 0, status, "cond_signal"); - } -} - -// JSR166 -// ------------------------------------------------------- - -// The solaris and linux implementations of park/unpark are fairly -// conservative for now, but can be improved. They currently use a -// mutex/condvar pair, plus _counter. -// Park decrements _counter if > 0, else does a condvar wait. Unpark -// sets count to 1 and signals condvar. Only one thread ever waits -// on the condvar. Contention seen when trying to park implies that someone -// is unparking you, so don't wait. And spurious returns are fine, so there -// is no need to track notifications. - -#define MAX_SECS 100000000 - -// This code is common to linux and solaris and will be moved to a -// common place in dolphin. -// -// The passed in time value is either a relative time in nanoseconds -// or an absolute time in milliseconds. Either way it has to be unpacked -// into suitable seconds and nanoseconds components and stored in the -// given timespec structure. -// Given time is a 64-bit value and the time_t used in the timespec is only -// a signed-32-bit value (except on 64-bit Linux) we have to watch for -// overflow if times way in the future are given. Further on Solaris versions -// prior to 10 there is a restriction (see cond_timedwait) that the specified -// number of seconds, in abstime, is less than current_time + 100,000,000. -// As it will be 28 years before "now + 100000000" will overflow we can -// ignore overflow and just impose a hard-limit on seconds using the value -// of "now + 100,000,000". This places a limit on the timeout of about 3.17 -// years from "now". -// -static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) { - assert(time > 0, "convertTime"); - - struct timeval now; - int status = gettimeofday(&now, NULL); - assert(status == 0, "gettimeofday"); - - time_t max_secs = now.tv_sec + MAX_SECS; - - if (isAbsolute) { - jlong secs = time / 1000; - if (secs > max_secs) { - absTime->tv_sec = max_secs; - } else { - absTime->tv_sec = secs; - } - absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC; - } else { - jlong secs = time / NANOSECS_PER_SEC; - if (secs >= MAX_SECS) { - absTime->tv_sec = max_secs; - absTime->tv_nsec = 0; - } else { - absTime->tv_sec = now.tv_sec + secs; - absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000; - if (absTime->tv_nsec >= NANOSECS_PER_SEC) { - absTime->tv_nsec -= NANOSECS_PER_SEC; - ++absTime->tv_sec; // note: this must be <= max_secs - } - } - } - assert(absTime->tv_sec >= 0, "tv_sec < 0"); - assert(absTime->tv_sec <= max_secs, "tv_sec > max_secs"); - assert(absTime->tv_nsec >= 0, "tv_nsec < 0"); - assert(absTime->tv_nsec < NANOSECS_PER_SEC, "tv_nsec >= nanos_per_sec"); -} - -void Parker::park(bool isAbsolute, jlong time) { - // Ideally we'd do something useful while spinning, such - // as calling unpackTime(). - - // Optional fast-path check: - // Return immediately if a permit is available. - // We depend on Atomic::xchg() having full barrier semantics - // since we are doing a lock-free update to _counter. - if (Atomic::xchg(&_counter, 0) > 0) return; - - // Optional fast-exit: Check interrupt before trying to wait - Thread* thread = Thread::current(); - assert(thread->is_Java_thread(), "Must be JavaThread"); - JavaThread *jt = (JavaThread *)thread; - if (jt->is_interrupted(false)) { - return; - } - - // First, demultiplex/decode time arguments - timespec absTime; - if (time < 0 || (isAbsolute && time == 0)) { // don't wait at all - return; - } - if (time > 0) { - // Warning: this code might be exposed to the old Solaris time - // round-down bugs. Grep "roundingFix" for details. - unpackTime(&absTime, isAbsolute, time); - } - - // Enter safepoint region - // Beware of deadlocks such as 6317397. - // The per-thread Parker:: _mutex is a classic leaf-lock. - // In particular a thread must never block on the Threads_lock while - // holding the Parker:: mutex. If safepoints are pending both the - // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock. - ThreadBlockInVM tbivm(jt); - - // Can't access interrupt state now that we are _thread_blocked. If we've - // been interrupted since we checked above then _counter will be > 0. - - // Don't wait if cannot get lock since interference arises from - // unblocking. - if (os::Solaris::mutex_trylock(_mutex) != 0) { - return; - } - - int status; - - if (_counter > 0) { // no wait needed - _counter = 0; - status = os::Solaris::mutex_unlock(_mutex); - assert(status == 0, "invariant"); - // Paranoia to ensure our locked and lock-free paths interact - // correctly with each other and Java-level accesses. - OrderAccess::fence(); - return; - } - - OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */); - jt->set_suspend_equivalent(); - // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self() - - // Do this the hard way by blocking ... - // See http://monaco.sfbay/detail.jsf?cr=5094058. - if (time == 0) { - status = os::Solaris::cond_wait(_cond, _mutex); - } else { - status = os::Solaris::cond_timedwait (_cond, _mutex, &absTime); - } - // Note that an untimed cond_wait() can sometimes return ETIME on older - // versions of the Solaris. - assert_status(status == 0 || status == EINTR || - status == ETIME || status == ETIMEDOUT, - status, "cond_timedwait"); - - _counter = 0; - status = os::Solaris::mutex_unlock(_mutex); - assert_status(status == 0, status, "mutex_unlock"); - // Paranoia to ensure our locked and lock-free paths interact - // correctly with each other and Java-level accesses. - OrderAccess::fence(); - - // If externally suspended while waiting, re-suspend - if (jt->handle_special_suspend_equivalent_condition()) { - jt->java_suspend_self(); - } -} - -void Parker::unpark() { - int status = os::Solaris::mutex_lock(_mutex); - assert(status == 0, "invariant"); - const int s = _counter; - _counter = 1; - status = os::Solaris::mutex_unlock(_mutex); - assert(status == 0, "invariant"); - - if (s < 1) { - status = os::Solaris::cond_signal(_cond); - assert(status == 0, "invariant"); - } -} - -// Platform Mutex/Monitor implementations - -os::PlatformMutex::PlatformMutex() { - int status = os::Solaris::mutex_init(&_mutex); - assert_status(status == 0, status, "mutex_init"); -} - -os::PlatformMutex::~PlatformMutex() { - int status = os::Solaris::mutex_destroy(&_mutex); - assert_status(status == 0, status, "mutex_destroy"); -} - -void os::PlatformMutex::lock() { - int status = os::Solaris::mutex_lock(&_mutex); - assert_status(status == 0, status, "mutex_lock"); -} - -void os::PlatformMutex::unlock() { - int status = os::Solaris::mutex_unlock(&_mutex); - assert_status(status == 0, status, "mutex_unlock"); -} - -bool os::PlatformMutex::try_lock() { - int status = os::Solaris::mutex_trylock(&_mutex); - assert_status(status == 0 || status == EBUSY, status, "mutex_trylock"); - return status == 0; -} - -os::PlatformMonitor::PlatformMonitor() { - int status = os::Solaris::cond_init(&_cond); - assert_status(status == 0, status, "cond_init"); -} - -os::PlatformMonitor::~PlatformMonitor() { - int status = os::Solaris::cond_destroy(&_cond); - assert_status(status == 0, status, "cond_destroy"); -} - -// Must already be locked -int os::PlatformMonitor::wait(jlong millis) { - assert(millis >= 0, "negative timeout"); - if (millis > 0) { - timestruc_t abst; - int ret = OS_TIMEOUT; - compute_abstime(&abst, millis); - int status = os::Solaris::cond_timedwait(&_cond, &_mutex, &abst); - assert_status(status == 0 || status == EINTR || - status == ETIME || status == ETIMEDOUT, - status, "cond_timedwait"); - // EINTR acts as spurious wakeup - which is permitted anyway - if (status == 0 || status == EINTR) { - ret = OS_OK; - } - return ret; - } else { - int status = os::Solaris::cond_wait(&_cond, &_mutex); - assert_status(status == 0 || status == EINTR, - status, "cond_wait"); - return OS_OK; - } -} - -void os::PlatformMonitor::notify() { - int status = os::Solaris::cond_signal(&_cond); - assert_status(status == 0, status, "cond_signal"); -} - -void os::PlatformMonitor::notify_all() { - int status = os::Solaris::cond_broadcast(&_cond); - assert_status(status == 0, status, "cond_broadcast"); -} - -extern char** environ; - -// Run the specified command in a separate process. Return its exit value, -// or -1 on failure (e.g. can't fork a new process). -// Unlike system(), this function can be called from signal handler. It -// doesn't block SIGINT et al. -int os::fork_and_exec(char* cmd, bool use_vfork_if_available) { - char * argv[4]; - argv[0] = (char *)"sh"; - argv[1] = (char *)"-c"; - argv[2] = cmd; - argv[3] = NULL; - - // fork is async-safe, fork1 is not so can't use in signal handler - pid_t pid; - Thread* t = Thread::current_or_null_safe(); - if (t != NULL && t->is_inside_signal_handler()) { - pid = fork(); - } else { - pid = fork1(); - } - - if (pid < 0) { - // fork failed - warning("fork failed: %s", os::strerror(errno)); - return -1; - - } else if (pid == 0) { - // child process - - // try to be consistent with system(), which uses "/usr/bin/sh" on Solaris - execve("/usr/bin/sh", argv, environ); - - // execve failed - _exit(-1); - - } else { - // copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't - // care about the actual exit code, for now. - - int status; - - // Wait for the child process to exit. This returns immediately if - // the child has already exited. */ - while (waitpid(pid, &status, 0) < 0) { - switch (errno) { - case ECHILD: return 0; - case EINTR: break; - default: return -1; - } - } - - if (WIFEXITED(status)) { - // The child exited normally; get its exit code. - return WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - // The child exited because of a signal - // The best value to return is 0x80 + signal number, - // because that is what all Unix shells do, and because - // it allows callers to distinguish between process exit and - // process death by signal. - return 0x80 + WTERMSIG(status); - } else { - // Unknown exit code; pass it through - return status; - } - } -} - -size_t os::write(int fd, const void *buf, unsigned int nBytes) { - size_t res; - RESTARTABLE((size_t) ::write(fd, buf, (size_t) nBytes), res); - return res; -} - -int os::close(int fd) { - return ::close(fd); -} - -int os::socket_close(int fd) { - return ::close(fd); -} - -int os::recv(int fd, char* buf, size_t nBytes, uint flags) { - assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, - "Assumed _thread_in_native"); - RESTARTABLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags)); -} - -int os::send(int fd, char* buf, size_t nBytes, uint flags) { - assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native, - "Assumed _thread_in_native"); - RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags)); -} - -int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { - RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags)); -} - -// As both poll and select can be interrupted by signals, we have to be -// prepared to restart the system call after updating the timeout, unless -// a poll() is done with timeout == -1, in which case we repeat with this -// "wait forever" value. - -int os::connect(int fd, struct sockaddr *him, socklen_t len) { - int _result; - _result = ::connect(fd, him, len); - - // On Solaris, when a connect() call is interrupted, the connection - // can be established asynchronously (see 6343810). Subsequent calls - // to connect() must check the errno value which has the semantic - // described below (copied from the connect() man page). Handling - // of asynchronously established connections is required for both - // blocking and non-blocking sockets. - // EINTR The connection attempt was interrupted - // before any data arrived by the delivery of - // a signal. The connection, however, will be - // established asynchronously. - // - // EINPROGRESS The socket is non-blocking, and the connec- - // tion cannot be completed immediately. - // - // EALREADY The socket is non-blocking, and a previous - // connection attempt has not yet been com- - // pleted. - // - // EISCONN The socket is already connected. - if (_result == OS_ERR && errno == EINTR) { - // restarting a connect() changes its errno semantics - RESTARTABLE(::connect(fd, him, len), _result); - // undo these changes - if (_result == OS_ERR) { - if (errno == EALREADY) { - errno = EINPROGRESS; // fall through - } else if (errno == EISCONN) { - errno = 0; - return OS_OK; - } - } - } - return _result; -} - -// Get the default path to the core file -// Returns the length of the string -int os::get_core_path(char* buffer, size_t bufferSize) { - const char* p = get_current_directory(buffer, bufferSize); - - if (p == NULL) { - assert(p != NULL, "failed to get current directory"); - return 0; - } - - jio_snprintf(buffer, bufferSize, "%s/core or core.%d", - p, current_process_id()); - - return strlen(buffer); -} - -bool os::supports_map_sync() { - return false; -} - -#ifndef PRODUCT -void TestReserveMemorySpecial_test() { - // No tests available for this platform -} -#endif - -bool os::start_debugging(char *buf, int buflen) { - int len = (int)strlen(buf); - char *p = &buf[len]; - - jio_snprintf(p, buflen-len, - "\n\n" - "Do you want to debug the problem?\n\n" - "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n" - "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" - "Otherwise, press RETURN to abort...", - os::current_process_id(), os::current_thread_id()); - - bool yes = os::message_box("Unexpected Error", buf); - - if (yes) { - // yes, user asked VM to launch debugger - jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id()); - - os::fork_and_exec(buf); - yes = false; - } - return yes; -} diff --git a/src/hotspot/os/solaris/os_solaris.hpp b/src/hotspot/os/solaris/os_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/os_solaris.hpp +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (c) 1997, 2020, 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. - * - */ - -#ifndef OS_SOLARIS_OS_SOLARIS_HPP -#define OS_SOLARIS_OS_SOLARIS_HPP - -// Solaris_OS defines the interface to Solaris operating systems - -// see thr_setprio(3T) for the basis of these numbers -#define MinimumPriority 0 -#define NormalPriority 64 -#define MaximumPriority 127 - -// FX/60 is critical thread class/priority on T4 -#define FXCriticalPriority 60 - -// Information about the protection of the page at address '0' on this os. -static bool zero_page_read_protected() { return true; } - -class Solaris { - friend class os; - - private: - - // Support for "new" libthread APIs for getting & setting thread context (2.8) -#define TRS_VALID 0 -#define TRS_NONVOLATILE 1 -#define TRS_LWPID 2 -#define TRS_INVALID 3 - - // initialized to libthread or lwp synchronization primitives depending on UseLWPSychronization - static int_fnP_mutex_tP _mutex_lock; - static int_fnP_mutex_tP _mutex_trylock; - static int_fnP_mutex_tP _mutex_unlock; - static int_fnP_mutex_tP_i_vP _mutex_init; - static int_fnP_mutex_tP _mutex_destroy; - static int _mutex_scope; - - static int_fnP_cond_tP_mutex_tP_timestruc_tP _cond_timedwait; - static int_fnP_cond_tP_mutex_tP _cond_wait; - static int_fnP_cond_tP _cond_signal; - static int_fnP_cond_tP _cond_broadcast; - static int_fnP_cond_tP_i_vP _cond_init; - static int_fnP_cond_tP _cond_destroy; - static int _cond_scope; - - static bool _synchronization_initialized; - - typedef uintptr_t lgrp_cookie_t; - typedef id_t lgrp_id_t; - typedef int lgrp_rsrc_t; - typedef enum lgrp_view { - LGRP_VIEW_CALLER, // what's available to the caller - LGRP_VIEW_OS // what's available to operating system - } lgrp_view_t; - - typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id); - typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view); - typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie); - typedef lgrp_id_t (*lgrp_root_func_t)(lgrp_cookie_t cookie); - typedef int (*lgrp_children_func_t)(lgrp_cookie_t cookie, lgrp_id_t parent, - lgrp_id_t *lgrp_array, uint_t lgrp_array_size); - typedef int (*lgrp_resources_func_t)(lgrp_cookie_t cookie, lgrp_id_t lgrp, - lgrp_id_t *lgrp_array, uint_t lgrp_array_size, - lgrp_rsrc_t type); - typedef int (*lgrp_nlgrps_func_t)(lgrp_cookie_t cookie); - typedef int (*lgrp_cookie_stale_func_t)(lgrp_cookie_t cookie); - - static lgrp_home_func_t _lgrp_home; - static lgrp_init_func_t _lgrp_init; - static lgrp_fini_func_t _lgrp_fini; - static lgrp_root_func_t _lgrp_root; - static lgrp_children_func_t _lgrp_children; - static lgrp_resources_func_t _lgrp_resources; - static lgrp_nlgrps_func_t _lgrp_nlgrps; - static lgrp_cookie_stale_func_t _lgrp_cookie_stale; - static lgrp_cookie_t _lgrp_cookie; - - // Large Page Support - static bool is_valid_page_size(size_t bytes); - static size_t page_size_for_alignment(size_t alignment); - static bool setup_large_pages(caddr_t start, size_t bytes, size_t align); - - static void try_enable_extended_io(); - - static struct sigaction *(*get_signal_action)(int); - static struct sigaction *get_preinstalled_handler(int); - static int (*get_libjsig_version)(); - static void save_preinstalled_handler(int, struct sigaction&); - static void check_signal_handler(int sig); - - typedef int (*pthread_setname_np_func_t)(pthread_t, const char*); - static pthread_setname_np_func_t _pthread_setname_np; - - public: - // Large Page Support--ISM. - static bool largepage_range(char* addr, size_t size); - - static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo - - static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect); - static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread, - const ucontext_t* uc); - - static ExtendedPC ucontext_get_ExtendedPC(const ucontext_t* uc); - static intptr_t* ucontext_get_sp(const ucontext_t* uc); - // ucontext_get_fp() is only used by Solaris X86 (see note below) - static intptr_t* ucontext_get_fp(const ucontext_t* uc); - static address ucontext_get_pc(const ucontext_t* uc); - static void ucontext_set_pc(ucontext_t* uc, address pc); - - // For Analyzer Forte AsyncGetCallTrace profiling support: - // Parameter ret_fp is only used by Solaris X86. - // - // We should have different declarations of this interface in - // os_solaris_i486.hpp and os_solaris_sparc.hpp, but that file - // provides extensions to the os class and not the Solaris class. - static ExtendedPC fetch_frame_from_ucontext(Thread* thread, const ucontext_t* uc, - intptr_t** ret_sp, intptr_t** ret_fp); - - static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr); - - static void hotspot_sigmask(Thread* thread); - - // SR_handler - static void SR_handler(Thread* thread, ucontext_t* uc); - - static void init_thread_fpu_state(void); - - protected: - // Solaris-specific interface goes here - static julong available_memory(); - static julong physical_memory() { return _physical_memory; } - static julong _physical_memory; - static void initialize_system_info(); - static int _dev_zero_fd; - static int get_dev_zero_fd() { return _dev_zero_fd; } - static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; } - static int commit_memory_impl(char* addr, size_t bytes, bool exec); - static int commit_memory_impl(char* addr, size_t bytes, - size_t alignment_hint, bool exec); - static char* mmap_chunk(char *addr, size_t size, int flags, int prot); - static char* anon_mmap(char* requested_addr, size_t bytes, size_t alignment_hint, bool fixed); - static bool mpss_sanity_check(bool warn, size_t * page_size); - - // Workaround for 4352906. thr_stksegment sometimes returns - // a bad value for the primordial thread's stack base when - // it is called more than one time. - // Workaround is to cache the initial value to avoid further - // calls to thr_stksegment. - // It appears that someone (Hotspot?) is trashing the user's - // proc_t structure (note that this is a system struct). - static address _main_stack_base; - - static void print_distro_info(outputStream* st); - static void print_libversion_info(outputStream* st); - - public: - static void libthread_init(); - static void synchronization_init(); - static bool liblgrp_init(); - // This boolean allows users to forward their own non-matching signals - // to JVM_handle_solaris_signal, harmlessly. - static bool signal_handlers_are_installed; - - static void signal_sets_init(); - static void install_signal_handlers(); - static void set_signal_handler(int sig, bool set_installed, bool oktochain); - static void init_signal_mem(); - static void set_our_sigflags(int, int); - static int get_our_sigflags(int); - - // For signal-chaining - static bool libjsig_is_loaded; // libjsig that interposes sigaction(), - // signal(), sigset() is loaded - static struct sigaction *get_chained_signal_action(int sig); - static bool chained_handler(int sig, siginfo_t *siginfo, void *context); - - // Allows us to switch between lwp and thread -based synchronization - static int mutex_lock(mutex_t *mx) { return _mutex_lock(mx); } - static int mutex_trylock(mutex_t *mx) { return _mutex_trylock(mx); } - static int mutex_unlock(mutex_t *mx) { return _mutex_unlock(mx); } - static int mutex_init(mutex_t *mx) { return _mutex_init(mx, os::Solaris::mutex_scope(), NULL); } - static int mutex_destroy(mutex_t *mx) { return _mutex_destroy(mx); } - static int mutex_scope() { return _mutex_scope; } - - static void set_mutex_lock(int_fnP_mutex_tP func) { _mutex_lock = func; } - static void set_mutex_trylock(int_fnP_mutex_tP func) { _mutex_trylock = func; } - static void set_mutex_unlock(int_fnP_mutex_tP func) { _mutex_unlock = func; } - static void set_mutex_init(int_fnP_mutex_tP_i_vP func) { _mutex_init = func; } - static void set_mutex_destroy(int_fnP_mutex_tP func) { _mutex_destroy = func; } - static void set_mutex_scope(int scope) { _mutex_scope = scope; } - - static int cond_timedwait(cond_t *cv, mutex_t *mx, timestruc_t *abst) { return _cond_timedwait(cv, mx, abst); } - static int cond_wait(cond_t *cv, mutex_t *mx) { return _cond_wait(cv, mx); } - static int cond_signal(cond_t *cv) { return _cond_signal(cv); } - static int cond_broadcast(cond_t *cv) { return _cond_broadcast(cv); } - static int cond_init(cond_t *cv) { return _cond_init(cv, os::Solaris::cond_scope(), NULL); } - static int cond_destroy(cond_t *cv) { return _cond_destroy(cv); } - static int cond_scope() { return _cond_scope; } - - static void set_cond_timedwait(int_fnP_cond_tP_mutex_tP_timestruc_tP func) { _cond_timedwait = func; } - static void set_cond_wait(int_fnP_cond_tP_mutex_tP func) { _cond_wait = func; } - static void set_cond_signal(int_fnP_cond_tP func) { _cond_signal = func; } - static void set_cond_broadcast(int_fnP_cond_tP func) { _cond_broadcast = func; } - static void set_cond_init(int_fnP_cond_tP_i_vP func) { _cond_init = func; } - static void set_cond_destroy(int_fnP_cond_tP func) { _cond_destroy = func; } - static void set_cond_scope(int scope) { _cond_scope = scope; } - - static bool synchronization_initialized() { return _synchronization_initialized; } - - static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; } - static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; } - static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; } - static void set_lgrp_root(lgrp_root_func_t func) { _lgrp_root = func; } - static void set_lgrp_children(lgrp_children_func_t func) { _lgrp_children = func; } - static void set_lgrp_resources(lgrp_resources_func_t func) { _lgrp_resources = func; } - static void set_lgrp_nlgrps(lgrp_nlgrps_func_t func) { _lgrp_nlgrps = func; } - static void set_lgrp_cookie_stale(lgrp_cookie_stale_func_t func) { _lgrp_cookie_stale = func; } - static void set_lgrp_cookie(lgrp_cookie_t cookie) { _lgrp_cookie = cookie; } - - static id_t lgrp_home(idtype_t type, id_t id) { return _lgrp_home != NULL ? _lgrp_home(type, id) : -1; } - static lgrp_cookie_t lgrp_init(lgrp_view_t view) { return _lgrp_init != NULL ? _lgrp_init(view) : 0; } - static int lgrp_fini(lgrp_cookie_t cookie) { return _lgrp_fini != NULL ? _lgrp_fini(cookie) : -1; } - static lgrp_id_t lgrp_root(lgrp_cookie_t cookie) { return _lgrp_root != NULL ? _lgrp_root(cookie) : -1; } - static int lgrp_children(lgrp_cookie_t cookie, lgrp_id_t parent, - lgrp_id_t *lgrp_array, uint_t lgrp_array_size) { - return _lgrp_children != NULL ? _lgrp_children(cookie, parent, lgrp_array, lgrp_array_size) : -1; - } - static int lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp, - lgrp_id_t *lgrp_array, uint_t lgrp_array_size, - lgrp_rsrc_t type) { - return _lgrp_resources != NULL ? _lgrp_resources(cookie, lgrp, lgrp_array, lgrp_array_size, type) : -1; - } - - static int lgrp_nlgrps(lgrp_cookie_t cookie) { return _lgrp_nlgrps != NULL ? _lgrp_nlgrps(cookie) : -1; } - static int lgrp_cookie_stale(lgrp_cookie_t cookie) { - return _lgrp_cookie_stale != NULL ? _lgrp_cookie_stale(cookie) : -1; - } - static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; } - - static sigset_t* unblocked_signals(); - static sigset_t* vm_signals(); - - // %%% Following should be promoted to os.hpp: - // Trace number of created threads - static jint _os_thread_limit; - static volatile jint _os_thread_count; - - static void correct_stack_boundaries_for_primordial_thread(Thread* thr); - - // Stack repair handling - - // none present - -}; - -class PlatformEvent : public CHeapObj { - private: - double CachePad[4]; // increase odds that _mutex is sole occupant of cache line - volatile int _Event; - int _nParked; - int _pipev[2]; - mutex_t _mutex[1]; - cond_t _cond[1]; - double PostPad[2]; - - protected: - // Defining a protected ctor effectively gives us an abstract base class. - // That is, a PlatformEvent can never be instantiated "naked" but only - // as a part of a ParkEvent (recall that ParkEvent extends PlatformEvent). - // TODO-FIXME: make dtor private - ~PlatformEvent() { guarantee(0, "invariant"); } - PlatformEvent() { - int status; - status = os::Solaris::cond_init(_cond); - assert_status(status == 0, status, "cond_init"); - status = os::Solaris::mutex_init(_mutex); - assert_status(status == 0, status, "mutex_init"); - _Event = 0; - _nParked = 0; - _pipev[0] = _pipev[1] = -1; - } - - public: - // Exercise caution using reset() and fired() -- they may require MEMBARs - void reset() { _Event = 0; } - int fired() { return _Event; } - void park(); - int park(jlong millis); - void unpark(); -}; - -class PlatformParker : public CHeapObj { - protected: - mutex_t _mutex[1]; - cond_t _cond[1]; - - public: // TODO-FIXME: make dtor private - ~PlatformParker() { guarantee(0, "invariant"); } - - public: - PlatformParker() { - int status; - status = os::Solaris::cond_init(_cond); - assert_status(status == 0, status, "cond_init"); - status = os::Solaris::mutex_init(_mutex); - assert_status(status == 0, status, "mutex_init"); - } -}; - -// Platform specific implementations that underpin VM Mutex/Monitor classes - -class PlatformMutex : public CHeapObj { - NONCOPYABLE(PlatformMutex); - - protected: - mutex_t _mutex; // Native mutex for locking - - public: - PlatformMutex(); - ~PlatformMutex(); - void lock(); - void unlock(); - bool try_lock(); -}; - -class PlatformMonitor : public PlatformMutex { - private: - cond_t _cond; // Native condition variable for blocking - - NONCOPYABLE(PlatformMonitor); - - public: - PlatformMonitor(); - ~PlatformMonitor(); - int wait(jlong millis); - void notify(); - void notify_all(); -}; - -#endif // OS_SOLARIS_OS_SOLARIS_HPP diff --git a/src/hotspot/os/solaris/os_solaris.inline.hpp b/src/hotspot/os/solaris/os_solaris.inline.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/os_solaris.inline.hpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef OS_SOLARIS_OS_SOLARIS_INLINE_HPP -#define OS_SOLARIS_OS_SOLARIS_INLINE_HPP - -#include "runtime/os.hpp" - -// System includes -#include -#include -#include -#include -#include -#include -#include -#include - -inline bool os::uses_stack_guard_pages() { - return true; -} - -inline bool os::must_commit_stack_guard_pages() { - assert(uses_stack_guard_pages(), "sanity check"); - int r = thr_main() ; - guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ; - return r; -} - - -// On Solaris, reservations are made on a page by page basis, nothing to do. -inline void os::pd_split_reserved_memory(char *base, size_t size, - size_t split, bool realloc) { -} - - -// Bang the shadow pages if they need to be touched to be mapped. -inline void os::map_stack_shadow_pages(address sp) { -} - -inline void os::dll_unload(void *lib) { ::dlclose(lib); } - -////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// macros for restartable system calls - -#define RESTARTABLE(_cmd, _result) do { \ - do { \ - _result = _cmd; \ - } while((_result == OS_ERR) && (errno == EINTR)); \ -} while(false) - -#define RESTARTABLE_RETURN_INT(_cmd) do { \ - int _result; \ - RESTARTABLE(_cmd, _result); \ - return _result; \ -} while(false) - -inline bool os::numa_has_static_binding() { return false; } -inline bool os::numa_has_group_homing() { return true; } - -inline int os::socket(int domain, int type, int protocol) { - return ::socket(domain, type, protocol); -} - -inline struct hostent* os::get_host_by_name(char* name) { - return ::gethostbyname(name); -} - -inline bool os::supports_monotonic_clock() { - // javaTimeNanos() is monotonic on Solaris, see getTimeNanos() comments - return true; -} - -inline void os::exit(int num) { - ::exit(num); -} - -#endif // OS_SOLARIS_OS_SOLARIS_INLINE_HPP diff --git a/src/hotspot/os/solaris/perfMemory_solaris.cpp b/src/hotspot/os/solaris/perfMemory_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/perfMemory_solaris.cpp +++ /dev/null @@ -1,1294 +0,0 @@ -/* - * Copyright (c) 2001, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "classfile/vmSymbols.hpp" -#include "logging/log.hpp" -#include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" -#include "oops/oop.inline.hpp" -#include "os_solaris.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/perfMemory.hpp" -#include "services/memTracker.hpp" -#include "utilities/exceptions.hpp" - -// put OS-includes here -#include -#include -#include -#include -#include -#include -#include -#include - -/* For POSIX-compliant getpwuid_r on Solaris */ -#define _POSIX_PTHREAD_SEMANTICS -#include - -static char* backing_store_file_name = NULL; // name of the backing store - // file, if successfully created. - -// Standard Memory Implementation Details - -// create the PerfData memory region in standard memory. -// -static char* create_standard_memory(size_t size) { - - // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size); - - if (mapAddress == NULL) { - return NULL; - } - - // commit memory - if (!os::commit_memory(mapAddress, size, !ExecMem)) { - if (PrintMiscellaneous && Verbose) { - warning("Could not commit PerfData memory\n"); - } - os::release_memory(mapAddress, size); - return NULL; - } - - return mapAddress; -} - -// delete the PerfData memory region -// -static void delete_standard_memory(char* addr, size_t size) { - - // there are no persistent external resources to cleanup for standard - // memory. since DestroyJavaVM does not support unloading of the JVM, - // cleanup of the memory resource is not performed. The memory will be - // reclaimed by the OS upon termination of the process. - // - return; -} - -// save the specified memory region to the given file -// -// Note: this function might be called from signal handler (by os::abort()), -// don't allocate heap memory. -// -static void save_memory_to_file(char* addr, size_t size) { - - const char* destfile = PerfMemory::get_perfdata_file_path(); - assert(destfile[0] != '\0', "invalid PerfData file path"); - - int result; - - RESTARTABLE(::open(destfile, O_CREAT|O_WRONLY|O_TRUNC, S_IREAD|S_IWRITE), - result);; - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("Could not create Perfdata save file: %s: %s\n", - destfile, os::strerror(errno)); - } - } else { - - int fd = result; - - for (size_t remaining = size; remaining > 0;) { - - RESTARTABLE(::write(fd, addr, remaining), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("Could not write Perfdata save file: %s: %s\n", - destfile, os::strerror(errno)); - } - break; - } - remaining -= (size_t)result; - addr += result; - } - - result = ::close(fd); - if (PrintMiscellaneous && Verbose) { - if (result == OS_ERR) { - warning("Could not close %s: %s\n", destfile, os::strerror(errno)); - } - } - } - FREE_C_HEAP_ARRAY(char, destfile); -} - - -// Shared Memory Implementation Details - -// Note: the solaris and linux shared memory implementation uses the mmap -// interface with a backing store file to implement named shared memory. -// Using the file system as the name space for shared memory allows a -// common name space to be supported across a variety of platforms. It -// also provides a name space that Java applications can deal with through -// simple file apis. -// -// The solaris and linux implementations store the backing store file in -// a user specific temporary directory located in the /tmp file system, -// which is always a local file system and is sometimes a RAM based file -// system. - -// return the user specific temporary directory name. -// -// the caller is expected to free the allocated memory. -// -static char* get_user_tmp_dir(const char* user) { - - const char* tmpdir = os::get_temp_directory(); - const char* perfdir = PERFDATA_NAME; - size_t nbytes = strlen(tmpdir) + strlen(perfdir) + strlen(user) + 3; - char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - - // construct the path name to user specific tmp directory - snprintf(dirname, nbytes, "%s/%s_%s", tmpdir, perfdir, user); - - return dirname; -} - -// convert the given file name into a process id. if the file -// does not meet the file naming constraints, return 0. -// -static pid_t filename_to_pid(const char* filename) { - - // a filename that doesn't begin with a digit is not a - // candidate for conversion. - // - if (!isdigit(*filename)) { - return 0; - } - - // check if file name can be converted to an integer without - // any leftover characters. - // - char* remainder = NULL; - errno = 0; - pid_t pid = (pid_t)strtol(filename, &remainder, 10); - - if (errno != 0) { - return 0; - } - - // check for left over characters. If any, then the filename is - // not a candidate for conversion. - // - if (remainder != NULL && *remainder != '\0') { - return 0; - } - - // successful conversion, return the pid - return pid; -} - - -// Check if the given statbuf is considered a secure directory for -// the backing store files. Returns true if the directory is considered -// a secure location. Returns false if the statbuf is a symbolic link or -// if an error occurred. -// -static bool is_statbuf_secure(struct stat *statp) { - if (S_ISLNK(statp->st_mode) || !S_ISDIR(statp->st_mode)) { - // The path represents a link or some non-directory file type, - // which is not what we expected. Declare it insecure. - // - return false; - } - // We have an existing directory, check if the permissions are safe. - // - if ((statp->st_mode & (S_IWGRP|S_IWOTH)) != 0) { - // The directory is open for writing and could be subjected - // to a symlink or a hard link attack. Declare it insecure. - // - return false; - } - // If user is not root then see if the uid of the directory matches the effective uid of the process. - uid_t euid = geteuid(); - if ((euid != 0) && (statp->st_uid != euid)) { - // The directory was not created by this user, declare it insecure. - // - return false; - } - return true; -} - - -// Check if the given path is considered a secure directory for -// the backing store files. Returns true if the directory exists -// and is considered a secure location. Returns false if the path -// is a symbolic link or if an error occurred. -// -static bool is_directory_secure(const char* path) { - struct stat statbuf; - int result = 0; - - RESTARTABLE(::lstat(path, &statbuf), result); - if (result == OS_ERR) { - return false; - } - - // The path exists, see if it is secure. - return is_statbuf_secure(&statbuf); -} - - -// Check if the given directory file descriptor is considered a secure -// directory for the backing store files. Returns true if the directory -// exists and is considered a secure location. Returns false if the path -// is a symbolic link or if an error occurred. -// -static bool is_dirfd_secure(int dir_fd) { - struct stat statbuf; - int result = 0; - - RESTARTABLE(::fstat(dir_fd, &statbuf), result); - if (result == OS_ERR) { - return false; - } - - // The path exists, now check its mode. - return is_statbuf_secure(&statbuf); -} - - -// Check to make sure fd1 and fd2 are referencing the same file system object. -// -static bool is_same_fsobject(int fd1, int fd2) { - struct stat statbuf1; - struct stat statbuf2; - int result = 0; - - RESTARTABLE(::fstat(fd1, &statbuf1), result); - if (result == OS_ERR) { - return false; - } - RESTARTABLE(::fstat(fd2, &statbuf2), result); - if (result == OS_ERR) { - return false; - } - - if ((statbuf1.st_ino == statbuf2.st_ino) && - (statbuf1.st_dev == statbuf2.st_dev)) { - return true; - } else { - return false; - } -} - - -// Open the directory of the given path and validate it. -// Return a DIR * of the open directory. -// -static DIR *open_directory_secure(const char* dirname) { - // Open the directory using open() so that it can be verified - // to be secure by calling is_dirfd_secure(), opendir() and then check - // to see if they are the same file system object. This method does not - // introduce a window of opportunity for the directory to be attacked that - // calling opendir() and is_directory_secure() does. - int result; - DIR *dirp = NULL; - RESTARTABLE(::open(dirname, O_RDONLY|O_NOFOLLOW), result); - if (result == OS_ERR) { - // Directory doesn't exist or is a symlink, so there is nothing to cleanup. - if (PrintMiscellaneous && Verbose) { - if (errno == ELOOP) { - warning("directory %s is a symlink and is not secure\n", dirname); - } else { - warning("could not open directory %s: %s\n", dirname, os::strerror(errno)); - } - } - return dirp; - } - int fd = result; - - // Determine if the open directory is secure. - if (!is_dirfd_secure(fd)) { - // The directory is not a secure directory. - os::close(fd); - return dirp; - } - - // Open the directory. - dirp = ::opendir(dirname); - if (dirp == NULL) { - // The directory doesn't exist, close fd and return. - os::close(fd); - return dirp; - } - - // Check to make sure fd and dirp are referencing the same file system object. - if (!is_same_fsobject(fd, dirp->d_fd)) { - // The directory is not secure. - os::close(fd); - os::closedir(dirp); - dirp = NULL; - return dirp; - } - - // Close initial open now that we know directory is secure - os::close(fd); - - return dirp; -} - -// NOTE: The code below uses fchdir(), open() and unlink() because -// fdopendir(), openat() and unlinkat() are not supported on all -// versions. Once the support for fdopendir(), openat() and unlinkat() -// is available on all supported versions the code can be changed -// to use these functions. - -// Open the directory of the given path, validate it and set the -// current working directory to it. -// Return a DIR * of the open directory and the saved cwd fd. -// -static DIR *open_directory_secure_cwd(const char* dirname, int *saved_cwd_fd) { - - // Open the directory. - DIR* dirp = open_directory_secure(dirname); - if (dirp == NULL) { - // Directory doesn't exist or is insecure, so there is nothing to cleanup. - return dirp; - } - int fd = dirp->d_fd; - - // Open a fd to the cwd and save it off. - int result; - RESTARTABLE(::open(".", O_RDONLY), result); - if (result == OS_ERR) { - *saved_cwd_fd = -1; - } else { - *saved_cwd_fd = result; - } - - // Set the current directory to dirname by using the fd of the directory and - // handle errors, otherwise shared memory files will be created in cwd. - result = fchdir(fd); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not change to directory %s", dirname); - } - if (*saved_cwd_fd != -1) { - ::close(*saved_cwd_fd); - *saved_cwd_fd = -1; - } - // Close the directory. - os::closedir(dirp); - return NULL; - } else { - return dirp; - } -} - -// Close the directory and restore the current working directory. -// -static void close_directory_secure_cwd(DIR* dirp, int saved_cwd_fd) { - - int result; - // If we have a saved cwd change back to it and close the fd. - if (saved_cwd_fd != -1) { - result = fchdir(saved_cwd_fd); - ::close(saved_cwd_fd); - } - - // Close the directory. - os::closedir(dirp); -} - -// Check if the given file descriptor is considered a secure. -// -static bool is_file_secure(int fd, const char *filename) { - - int result; - struct stat statbuf; - - // Determine if the file is secure. - RESTARTABLE(::fstat(fd, &statbuf), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("fstat failed on %s: %s\n", filename, os::strerror(errno)); - } - return false; - } - if (statbuf.st_nlink > 1) { - // A file with multiple links is not expected. - if (PrintMiscellaneous && Verbose) { - warning("file %s has multiple links\n", filename); - } - return false; - } - return true; -} - -// return the user name for the given user id -// -// the caller is expected to free the allocated memory. -// -static char* get_user_name(uid_t uid) { - - struct passwd pwent; - - // determine the max pwbuf size from sysconf, and hardcode - // a default if this not available through sysconf. - // - long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == -1) - bufsize = 1024; - - char* pwbuf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); - - struct passwd* p = NULL; - int result = getpwuid_r(uid, &pwent, pwbuf, (size_t)bufsize, &p); - - if (p == NULL || p->pw_name == NULL || *(p->pw_name) == '\0') { - if (PrintMiscellaneous && Verbose) { - if (p == NULL) { - warning("Could not retrieve passwd entry: %s\n", - os::strerror(errno)); - } - else { - warning("Could not determine user name: %s\n", - p->pw_name == NULL ? "pw_name = NULL" : - "pw_name zero length"); - } - } - FREE_C_HEAP_ARRAY(char, pwbuf); - return NULL; - } - - char* user_name = NEW_C_HEAP_ARRAY(char, strlen(p->pw_name) + 1, mtInternal); - strcpy(user_name, p->pw_name); - - FREE_C_HEAP_ARRAY(char, pwbuf); - return user_name; -} - -// return the name of the user that owns the process identified by vmid. -// -// This method uses a slow directory search algorithm to find the backing -// store file for the specified vmid and returns the user name, as determined -// by the user name suffix of the hsperfdata_ directory name. -// -// the caller is expected to free the allocated memory. -// -static char* get_user_name_slow(int vmid, TRAPS) { - - // short circuit the directory search if the process doesn't even exist. - if (kill(vmid, 0) == OS_ERR) { - if (errno == ESRCH) { - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found"); - } - else /* EPERM */ { - THROW_MSG_0(vmSymbols::java_io_IOException(), os::strerror(errno)); - } - } - - // directory search - char* oldest_user = NULL; - time_t oldest_ctime = 0; - - const char* tmpdirname = os::get_temp_directory(); - - // open the temp directory - DIR* tmpdirp = os::opendir(tmpdirname); - - if (tmpdirp == NULL) { - // Cannot open the directory to get the user name, return. - return NULL; - } - - // for each entry in the directory that matches the pattern hsperfdata_*, - // open the directory and check if the file for the given vmid exists. - // The file with the expected name and the latest creation date is used - // to determine the user name for the process id. - // - struct dirent* dentry; - errno = 0; - while ((dentry = os::readdir(tmpdirp)) != NULL) { - - // check if the directory entry is a hsperfdata file - if (strncmp(dentry->d_name, PERFDATA_NAME, strlen(PERFDATA_NAME)) != 0) { - continue; - } - - char* usrdir_name = NEW_C_HEAP_ARRAY(char, - strlen(tmpdirname) + strlen(dentry->d_name) + 2, mtInternal); - strcpy(usrdir_name, tmpdirname); - strcat(usrdir_name, "/"); - strcat(usrdir_name, dentry->d_name); - - // open the user directory - DIR* subdirp = open_directory_secure(usrdir_name); - - if (subdirp == NULL) { - FREE_C_HEAP_ARRAY(char, usrdir_name); - continue; - } - - // Since we don't create the backing store files in directories - // pointed to by symbolic links, we also don't follow them when - // looking for the files. We check for a symbolic link after the - // call to opendir in order to eliminate a small window where the - // symlink can be exploited. - // - if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name); - os::closedir(subdirp); - continue; - } - - struct dirent* udentry; - errno = 0; - while ((udentry = os::readdir(subdirp)) != NULL) { - - if (filename_to_pid(udentry->d_name) == vmid) { - struct stat statbuf; - int result; - - char* filename = NEW_C_HEAP_ARRAY(char, - strlen(usrdir_name) + strlen(udentry->d_name) + 2, mtInternal); - - strcpy(filename, usrdir_name); - strcat(filename, "/"); - strcat(filename, udentry->d_name); - - // don't follow symbolic links for the file - RESTARTABLE(::lstat(filename, &statbuf), result); - if (result == OS_ERR) { - FREE_C_HEAP_ARRAY(char, filename); - continue; - } - - // skip over files that are not regular files. - if (!S_ISREG(statbuf.st_mode)) { - FREE_C_HEAP_ARRAY(char, filename); - continue; - } - - // compare and save filename with latest creation time - if (statbuf.st_size > 0 && statbuf.st_ctime > oldest_ctime) { - - if (statbuf.st_ctime > oldest_ctime) { - char* user = strchr(dentry->d_name, '_') + 1; - - FREE_C_HEAP_ARRAY(char, oldest_user); - oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); - - strcpy(oldest_user, user); - oldest_ctime = statbuf.st_ctime; - } - } - - FREE_C_HEAP_ARRAY(char, filename); - } - } - os::closedir(subdirp); - FREE_C_HEAP_ARRAY(char, usrdir_name); - } - os::closedir(tmpdirp); - - return(oldest_user); -} - -// return the name of the user that owns the JVM indicated by the given vmid. -// -static char* get_user_name(int vmid, TRAPS) { - - char psinfo_name[PATH_MAX]; - int result; - - snprintf(psinfo_name, PATH_MAX, "/proc/%d/psinfo", vmid); - - RESTARTABLE(::open(psinfo_name, O_RDONLY), result); - - if (result != OS_ERR) { - int fd = result; - - psinfo_t psinfo; - char* addr = (char*)&psinfo; - - for (size_t remaining = sizeof(psinfo_t); remaining > 0;) { - - RESTARTABLE(::read(fd, addr, remaining), result); - if (result == OS_ERR) { - ::close(fd); - THROW_MSG_0(vmSymbols::java_io_IOException(), "Read error"); - } else { - remaining-=result; - addr+=result; - } - } - - ::close(fd); - - // get the user name for the effective user id of the process - char* user_name = get_user_name(psinfo.pr_euid); - - return user_name; - } - - if (result == OS_ERR && errno == EACCES) { - - // In this case, the psinfo file for the process id existed, - // but we didn't have permission to access it. - THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), - os::strerror(errno)); - } - - // at this point, we don't know if the process id itself doesn't - // exist or if the psinfo file doesn't exit. If the psinfo file - // doesn't exist, then we are running on Solaris 2.5.1 or earlier. - // since the structured procfs and old procfs interfaces can't be - // mixed, we attempt to find the file through a directory search. - - return get_user_name_slow(vmid, THREAD); -} - -// return the file name of the backing store file for the named -// shared memory region for the given user name and vmid. -// -// the caller is expected to free the allocated memory. -// -static char* get_sharedmem_filename(const char* dirname, int vmid) { - - // add 2 for the file separator and a NULL terminator. - size_t nbytes = strlen(dirname) + UINT_CHARS + 2; - - char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - snprintf(name, nbytes, "%s/%d", dirname, vmid); - - return name; -} - - -// remove file -// -// this method removes the file specified by the given path -// -static void remove_file(const char* path) { - - int result; - - // if the file is a directory, the following unlink will fail. since - // we don't expect to find directories in the user temp directory, we - // won't try to handle this situation. even if accidentially or - // maliciously planted, the directory's presence won't hurt anything. - // - RESTARTABLE(::unlink(path), result); - if (PrintMiscellaneous && Verbose && result == OS_ERR) { - if (errno != ENOENT) { - warning("Could not unlink shared memory backing" - " store file %s : %s\n", path, os::strerror(errno)); - } - } -} - - -// cleanup stale shared memory resources -// -// This method attempts to remove all stale shared memory files in -// the named user temporary directory. It scans the named directory -// for files matching the pattern ^$[0-9]*$. For each file found, the -// process id is extracted from the file name and a test is run to -// determine if the process is alive. If the process is not alive, -// any stale file resources are removed. -// -static void cleanup_sharedmem_resources(const char* dirname) { - - int saved_cwd_fd; - // open the directory - DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); - if (dirp == NULL) { - // directory doesn't exist or is insecure, so there is nothing to cleanup - return; - } - - // for each entry in the directory that matches the expected file - // name pattern, determine if the file resources are stale and if - // so, remove the file resources. Note, instrumented HotSpot processes - // for this user may start and/or terminate during this search and - // remove or create new files in this directory. The behavior of this - // loop under these conditions is dependent upon the implementation of - // opendir/readdir. - // - struct dirent* entry; - errno = 0; - while ((entry = os::readdir(dirp)) != NULL) { - - pid_t pid = filename_to_pid(entry->d_name); - - if (pid == 0) { - - if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - - // attempt to remove all unexpected files, except "." and ".." - unlink(entry->d_name); - } - - errno = 0; - continue; - } - - // we now have a file name that converts to a valid integer - // that could represent a process id . if this process id - // matches the current process id or the process is not running, - // then remove the stale file resources. - // - // process liveness is detected by sending signal number 0 to - // the process id (see kill(2)). if kill determines that the - // process does not exist, then the file resources are removed. - // if kill determines that that we don't have permission to - // signal the process, then the file resources are assumed to - // be stale and are removed because the resources for such a - // process should be in a different user specific directory. - // - if ((pid == os::current_process_id()) || - (kill(pid, 0) == OS_ERR && (errno == ESRCH || errno == EPERM))) { - - unlink(entry->d_name); - } - errno = 0; - } - - // close the directory and reset the current working directory - close_directory_secure_cwd(dirp, saved_cwd_fd); -} - -// make the user specific temporary directory. Returns true if -// the directory exists and is secure upon return. Returns false -// if the directory exists but is either a symlink, is otherwise -// insecure, or if an error occurred. -// -static bool make_user_tmp_dir(const char* dirname) { - - // create the directory with 0755 permissions. note that the directory - // will be owned by euid::egid, which may not be the same as uid::gid. - // - if (mkdir(dirname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == OS_ERR) { - if (errno == EEXIST) { - // The directory already exists and was probably created by another - // JVM instance. However, this could also be the result of a - // deliberate symlink. Verify that the existing directory is safe. - // - if (!is_directory_secure(dirname)) { - // directory is not secure - if (PrintMiscellaneous && Verbose) { - warning("%s directory is insecure\n", dirname); - } - return false; - } - } - else { - // we encountered some other failure while attempting - // to create the directory - // - if (PrintMiscellaneous && Verbose) { - warning("could not create directory %s: %s\n", - dirname, os::strerror(errno)); - } - return false; - } - } - return true; -} - -// create the shared memory file resources -// -// This method creates the shared memory file with the given size -// This method also creates the user specific temporary directory, if -// it does not yet exist. -// -static int create_sharedmem_resources(const char* dirname, const char* filename, size_t size) { - - // make the user temporary directory - if (!make_user_tmp_dir(dirname)) { - // could not make/find the directory or the found directory - // was not secure - return -1; - } - - int saved_cwd_fd; - // open the directory and set the current working directory to it - DIR* dirp = open_directory_secure_cwd(dirname, &saved_cwd_fd); - if (dirp == NULL) { - // Directory doesn't exist or is insecure, so cannot create shared - // memory file. - return -1; - } - - // Open the filename in the current directory. - // Cannot use O_TRUNC here; truncation of an existing file has to happen - // after the is_file_secure() check below. - int result; - RESTARTABLE(::open(filename, O_RDWR|O_CREAT|O_NOFOLLOW, S_IREAD|S_IWRITE), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - if (errno == ELOOP) { - warning("file %s is a symlink and is not secure\n", filename); - } else { - warning("could not create file %s: %s\n", filename, os::strerror(errno)); - } - } - // close the directory and reset the current working directory - close_directory_secure_cwd(dirp, saved_cwd_fd); - - return -1; - } - // close the directory and reset the current working directory - close_directory_secure_cwd(dirp, saved_cwd_fd); - - // save the file descriptor - int fd = result; - - // check to see if the file is secure - if (!is_file_secure(fd, filename)) { - ::close(fd); - return -1; - } - - // truncate the file to get rid of any existing data - RESTARTABLE(::ftruncate(fd, (off_t)0), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not truncate shared memory file: %s\n", os::strerror(errno)); - } - ::close(fd); - return -1; - } - // set the file size - RESTARTABLE(::ftruncate(fd, (off_t)size), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("could not set shared memory file size: %s\n", os::strerror(errno)); - } - ::close(fd); - return -1; - } - - return fd; -} - -// open the shared memory file for the given user and vmid. returns -// the file descriptor for the open file or -1 if the file could not -// be opened. -// -static int open_sharedmem_file(const char* filename, int oflags, TRAPS) { - - // open the file - int result; - RESTARTABLE(::open(filename, oflags), result); - if (result == OS_ERR) { - if (errno == ENOENT) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found", OS_ERR); - } - else if (errno == EACCES) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Permission denied", OS_ERR); - } - else { - THROW_MSG_(vmSymbols::java_io_IOException(), - os::strerror(errno), OS_ERR); - } - } - int fd = result; - - // check to see if the file is secure - if (!is_file_secure(fd, filename)) { - ::close(fd); - return -1; - } - - return fd; -} - -// create a named shared memory region. returns the address of the -// memory region on success or NULL on failure. A return value of -// NULL will ultimately disable the shared memory feature. -// -// On Solaris, the name space for shared memory objects -// is the file system name space. -// -// A monitoring application attaching to a JVM does not need to know -// the file system name of the shared memory object. However, it may -// be convenient for applications to discover the existence of newly -// created and terminating JVMs by watching the file system name space -// for files being created or removed. -// -static char* mmap_create_shared(size_t size) { - - int result; - int fd; - char* mapAddress; - - int vmid = os::current_process_id(); - - char* user_name = get_user_name(geteuid()); - - if (user_name == NULL) - return NULL; - - char* dirname = get_user_tmp_dir(user_name); - char* filename = get_sharedmem_filename(dirname, vmid); - - // get the short filename - char* short_filename = strrchr(filename, '/'); - if (short_filename == NULL) { - short_filename = filename; - } else { - short_filename++; - } - - // cleanup any stale shared memory files - cleanup_sharedmem_resources(dirname); - - assert(((size > 0) && (size % os::vm_page_size() == 0)), - "unexpected PerfMemory region size"); - - fd = create_sharedmem_resources(dirname, short_filename, size); - - FREE_C_HEAP_ARRAY(char, user_name); - FREE_C_HEAP_ARRAY(char, dirname); - - if (fd == -1) { - FREE_C_HEAP_ARRAY(char, filename); - return NULL; - } - - mapAddress = (char*)::mmap((char*)0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - - result = ::close(fd); - assert(result != OS_ERR, "could not close file"); - - if (mapAddress == MAP_FAILED) { - if (PrintMiscellaneous && Verbose) { - warning("mmap failed - %s\n", os::strerror(errno)); - } - remove_file(filename); - FREE_C_HEAP_ARRAY(char, filename); - return NULL; - } - - // save the file name for use in delete_shared_memory() - backing_store_file_name = filename; - - // clear the shared memory region - (void)::memset((void*) mapAddress, 0, size); - - // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, - size, CURRENT_PC, mtInternal); - - return mapAddress; -} - -// release a named shared memory region -// -static void unmap_shared(char* addr, size_t bytes) { - os::release_memory(addr, bytes); -} - -// create the PerfData memory region in shared memory. -// -static char* create_shared_memory(size_t size) { - - // create the shared memory region. - return mmap_create_shared(size); -} - -// delete the shared PerfData memory region -// -static void delete_shared_memory(char* addr, size_t size) { - - // cleanup the persistent shared memory resources. since DestroyJavaVM does - // not support unloading of the JVM, unmapping of the memory resource is - // not performed. The memory will be reclaimed by the OS upon termination of - // the process. The backing store file is deleted from the file system. - - assert(!PerfDisableSharedMem, "shouldn't be here"); - - if (backing_store_file_name != NULL) { - remove_file(backing_store_file_name); - // Don't.. Free heap memory could deadlock os::abort() if it is called - // from signal handler. OS will reclaim the heap memory. - // FREE_C_HEAP_ARRAY(char, backing_store_file_name); - backing_store_file_name = NULL; - } -} - -// return the size of the file for the given file descriptor -// or 0 if it is not a valid size for a shared memory file -// -static size_t sharedmem_filesize(int fd, TRAPS) { - - struct stat statbuf; - int result; - - RESTARTABLE(::fstat(fd, &statbuf), result); - if (result == OS_ERR) { - if (PrintMiscellaneous && Verbose) { - warning("fstat failed: %s\n", os::strerror(errno)); - } - THROW_MSG_0(vmSymbols::java_io_IOException(), - "Could not determine PerfMemory size"); - } - - if ((statbuf.st_size == 0) || - ((size_t)statbuf.st_size % os::vm_page_size() != 0)) { - THROW_MSG_0(vmSymbols::java_io_IOException(), - "Invalid PerfMemory size"); - } - - return (size_t)statbuf.st_size; -} - -// attach to a named shared memory region. -// -static void mmap_attach_shared(const char* user, int vmid, PerfMemory::PerfMemoryMode mode, char** addr, size_t* sizep, TRAPS) { - - char* mapAddress; - int result; - int fd; - size_t size = 0; - const char* luser = NULL; - - int mmap_prot; - int file_flags; - - ResourceMark rm; - - // map the high level access mode to the appropriate permission - // constructs for the file and the shared memory mapping. - if (mode == PerfMemory::PERF_MODE_RO) { - mmap_prot = PROT_READ; - file_flags = O_RDONLY | O_NOFOLLOW; - } - else if (mode == PerfMemory::PERF_MODE_RW) { -#ifdef LATER - mmap_prot = PROT_READ | PROT_WRITE; - file_flags = O_RDWR | O_NOFOLLOW; -#else - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Unsupported access mode"); -#endif - } - else { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Illegal access mode"); - } - - if (user == NULL || strlen(user) == 0) { - luser = get_user_name(vmid, CHECK); - } - else { - luser = user; - } - - if (luser == NULL) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Could not map vmid to user Name"); - } - - char* dirname = get_user_tmp_dir(luser); - - // since we don't follow symbolic links when creating the backing - // store file, we don't follow them when attaching either. - // - if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - if (luser != user) { - FREE_C_HEAP_ARRAY(char, luser); - } - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "Process not found"); - } - - char* filename = get_sharedmem_filename(dirname, vmid); - - // copy heap memory to resource memory. the open_sharedmem_file - // method below need to use the filename, but could throw an - // exception. using a resource array prevents the leak that - // would otherwise occur. - char* rfilename = NEW_RESOURCE_ARRAY(char, strlen(filename) + 1); - strcpy(rfilename, filename); - - // free the c heap resources that are no longer needed - if (luser != user) FREE_C_HEAP_ARRAY(char, luser); - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, filename); - - // open the shared memory file for the give vmid - fd = open_sharedmem_file(rfilename, file_flags, THREAD); - - if (fd == OS_ERR) { - return; - } - - if (HAS_PENDING_EXCEPTION) { - ::close(fd); - return; - } - - if (*sizep == 0) { - size = sharedmem_filesize(fd, CHECK); - } else { - size = *sizep; - } - - assert(size > 0, "unexpected size <= 0"); - - mapAddress = (char*)::mmap((char*)0, size, mmap_prot, MAP_SHARED, fd, 0); - - result = ::close(fd); - assert(result != OS_ERR, "could not close file"); - - if (mapAddress == MAP_FAILED) { - if (PrintMiscellaneous && Verbose) { - warning("mmap failed: %s\n", os::strerror(errno)); - } - THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), - "Could not map PerfMemory"); - } - - // it does not go through os api, the operation has to record from here - MemTracker::record_virtual_memory_reserve_and_commit((address)mapAddress, - size, CURRENT_PC, mtInternal); - - *addr = mapAddress; - *sizep = size; - - log_debug(perf, memops)("mapped " SIZE_FORMAT " bytes for vmid %d at " - INTPTR_FORMAT, size, vmid, (void*)mapAddress); -} - -// create the PerfData memory region -// -// This method creates the memory region used to store performance -// data for the JVM. The memory may be created in standard or -// shared memory. -// -void PerfMemory::create_memory_region(size_t size) { - - if (PerfDisableSharedMem) { - // do not share the memory for the performance data. - _start = create_standard_memory(size); - } - else { - _start = create_shared_memory(size); - if (_start == NULL) { - - // creation of the shared memory region failed, attempt - // to create a contiguous, non-shared memory region instead. - // - if (PrintMiscellaneous && Verbose) { - warning("Reverting to non-shared PerfMemory region.\n"); - } - PerfDisableSharedMem = true; - _start = create_standard_memory(size); - } - } - - if (_start != NULL) _capacity = size; - -} - -// delete the PerfData memory region -// -// This method deletes the memory region used to store performance -// data for the JVM. The memory region indicated by the -// tuple will be inaccessible after a call to this method. -// -void PerfMemory::delete_memory_region() { - - assert((start() != NULL && capacity() > 0), "verify proper state"); - - // If user specifies PerfDataSaveFile, it will save the performance data - // to the specified file name no matter whether PerfDataSaveToFile is specified - // or not. In other word, -XX:PerfDataSaveFile=.. overrides flag - // -XX:+PerfDataSaveToFile. - if (PerfDataSaveToFile || PerfDataSaveFile != NULL) { - save_memory_to_file(start(), capacity()); - } - - if (PerfDisableSharedMem) { - delete_standard_memory(start(), capacity()); - } - else { - delete_shared_memory(start(), capacity()); - } -} - -// attach to the PerfData memory region for another JVM -// -// This method returns an tuple that points to -// a memory buffer that is kept reasonably synchronized with -// the PerfData memory region for the indicated JVM. This -// buffer may be kept in synchronization via shared memory -// or some other mechanism that keeps the buffer updated. -// -// If the JVM chooses not to support the attachability feature, -// this method should throw an UnsupportedOperation exception. -// -// This implementation utilizes named shared memory to map -// the indicated process's PerfData memory region into this JVMs -// address space. -// -void PerfMemory::attach(const char* user, int vmid, PerfMemoryMode mode, char** addrp, size_t* sizep, TRAPS) { - - if (vmid == 0 || vmid == os::current_process_id()) { - *addrp = start(); - *sizep = capacity(); - return; - } - - mmap_attach_shared(user, vmid, mode, addrp, sizep, CHECK); -} - -// detach from the PerfData memory region of another JVM -// -// This method detaches the PerfData memory region of another -// JVM, specified as an tuple of a buffer -// in this process's address space. This method may perform -// arbitrary actions to accomplish the detachment. The memory -// region specified by will be inaccessible after -// a call to this method. -// -// If the JVM chooses not to support the attachability feature, -// this method should throw an UnsupportedOperation exception. -// -// This implementation utilizes named shared memory to detach -// the indicated process's PerfData memory region from this -// process's address space. -// -void PerfMemory::detach(char* addr, size_t bytes, TRAPS) { - - assert(addr != 0, "address sanity check"); - assert(bytes > 0, "capacity sanity check"); - - if (PerfMemory::contains(addr) || PerfMemory::contains(addr + bytes - 1)) { - // prevent accidental detachment of this process's PerfMemory region - return; - } - - unmap_shared(addr, bytes); -} diff --git a/src/hotspot/os/solaris/threadCritical_solaris.cpp b/src/hotspot/os/solaris/threadCritical_solaris.cpp deleted file mode 100644 --- a/src/hotspot/os/solaris/threadCritical_solaris.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2001, 2016, 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. - * - */ - -#include "precompiled.hpp" -#include "runtime/os.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/threadCritical.hpp" - -// OS-includes here -#include -#include - -// -// See threadCritical.hpp for details of this class. -// -// For some reason, we don't do locking until the -// os::init() call completes. I'm not sure why this -// is, and have left it that way for now. This should -// be reviewed later. - -static mutex_t global_mut; -static thread_t global_mut_owner = -1; -static int global_mut_count = 0; - -ThreadCritical::ThreadCritical() { - if (os::Solaris::synchronization_initialized()) { - thread_t owner = thr_self(); - if (global_mut_owner != owner) { - if (os::Solaris::mutex_lock(&global_mut)) - fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)", - os::strerror(errno)); - assert(global_mut_count == 0, "must have clean count"); - assert(global_mut_owner == -1, "must have clean owner"); - } - global_mut_owner = owner; - ++global_mut_count; - } else { - assert (Threads::number_of_threads() == 0, "valid only during initialization"); - } -} - -ThreadCritical::~ThreadCritical() { - if (os::Solaris::synchronization_initialized()) { - assert(global_mut_owner == thr_self(), "must have correct owner"); - assert(global_mut_count > 0, "must have correct count"); - --global_mut_count; - if (global_mut_count == 0) { - global_mut_owner = -1; - if (os::Solaris::mutex_unlock(&global_mut)) - fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", os::strerror(errno)); - } - } else { - assert (Threads::number_of_threads() == 0, "valid only during initialization"); - } -} diff --git a/src/hotspot/os/solaris/vmStructs_solaris.hpp b/src/hotspot/os/solaris/vmStructs_solaris.hpp deleted file mode 100644 --- a/src/hotspot/os/solaris/vmStructs_solaris.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2015, 2019, 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. - * - */ - -#ifndef OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP -#define OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP - -// These are the OS-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) - -#define VM_TYPES_OS(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) \ - declare_unsigned_integer_type(OSThread::thread_id_t) - -#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) - -#endif // OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP diff --git a/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp b/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp --- a/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp +++ b/src/hotspot/os_cpu/bsd_x86/bytes_bsd_x86.inline.hpp @@ -85,18 +85,7 @@ #ifdef AMD64 inline u8 Bytes::swap_u8(u8 x) { -#ifdef SPARC_WORKS - // workaround for SunStudio12 CR6615391 - __asm__ __volatile__ ( - "bswapq %0" - :"=r" (x) // output : register 0 => x - :"0" (x) // input : x => register 0 - :"0" // clobbered register - ); - return x; -#else return bswap_64(x); -#endif } #else // Helper function for swap_u8 diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -283,10 +283,6 @@ void *esp; __asm__("mov %%" SPELL_REG_SP ", %0":"=r"(esp)); return (address) esp; -#elif defined(SPARC_WORKS) - void *esp; - __asm__("mov %%" SPELL_REG_SP ", %0":"=r"(esp)); - return (address) ((char*)esp + sizeof(long)*2); #else register void *esp __asm__ (SPELL_REG_SP); return (address) esp; @@ -411,7 +407,7 @@ } intptr_t* _get_previous_fp() { -#if defined(SPARC_WORKS) || defined(__clang__) || defined(__llvm__) +#if defined(__clang__) || defined(__llvm__) intptr_t **ebp; __asm__("mov %%" SPELL_REG_FP ", %0":"=r"(ebp)); #else diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -90,14 +90,8 @@ // Must never look like an address returned by reserve_memory, // even in its subfields (as defined by the CPU immediate fields, // if the CPU splits constants across multiple instructions). -#ifdef SPARC - // On SPARC, 0 != %hi(any real address), because there is no - // allocation in the first 1Kb of the virtual address space. - return (char *) 0; -#else // This is the value for x86; works pretty well for PPC too. return (char *) -1; -#endif // SPARC } address os::Bsd::ucontext_get_pc(const ucontext_t* uc) { diff --git a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_ATOMIC_LINUX_SPARC_HPP -#define OS_CPU_LINUX_SPARC_ATOMIC_LINUX_SPARC_HPP - -// Implementation of class atomic - -template -struct Atomic::PlatformAdd { - template - D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const; - - template - D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { - return add_and_fetch(dest, add_value, order) - add_value; - } -}; - -template<> -template -inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(I)); - STATIC_ASSERT(4 == sizeof(D)); - - D rv; - __asm__ volatile( - "1: \n\t" - " ld [%2], %%o2\n\t" - " add %1, %%o2, %%o3\n\t" - " cas [%2], %%o2, %%o3\n\t" - " cmp %%o2, %%o3\n\t" - " bne 1b\n\t" - " nop\n\t" - " add %1, %%o2, %0\n\t" - : "=r" (rv) - : "r" (add_value), "r" (dest) - : "memory", "o2", "o3"); - return rv; -} - -template<> -template -inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(I)); - STATIC_ASSERT(8 == sizeof(D)); - - D rv; - __asm__ volatile( - "1: \n\t" - " ldx [%2], %%o2\n\t" - " add %1, %%o2, %%o3\n\t" - " casx [%2], %%o2, %%o3\n\t" - " cmp %%o2, %%o3\n\t" - " bne %%xcc, 1b\n\t" - " nop\n\t" - " add %1, %%o2, %0\n\t" - : "=r" (rv) - : "r" (add_value), "r" (dest) - : "memory", "o2", "o3"); - return rv; -} - -template<> -template -inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(T)); - T rv = exchange_value; - __asm__ volatile( - " swap [%2],%1\n\t" - : "=r" (rv) - : "0" (exchange_value) /* we use same register as for return value */, "r" (dest) - : "memory"); - return rv; -} - -template<> -template -inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - T rv = exchange_value; - __asm__ volatile( - "1:\n\t" - " mov %1, %%o3\n\t" - " ldx [%2], %%o2\n\t" - " casx [%2], %%o2, %%o3\n\t" - " cmp %%o2, %%o3\n\t" - " bne %%xcc, 1b\n\t" - " nop\n\t" - " mov %%o2, %0\n\t" - : "=r" (rv) - : "r" (exchange_value), "r" (dest) - : "memory", "o2", "o3"); - return rv; -} - -// No direct support for cmpxchg of bytes; emulate using int. -template<> -struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; - -template<> -template -inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(T)); - T rv; - __asm__ volatile( - " cas [%2], %3, %0" - : "=r" (rv) - : "0" (exchange_value), "r" (dest), "r" (compare_value) - : "memory"); - return rv; -} - -template<> -template -inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - T rv; - __asm__ volatile( - " casx [%2], %3, %0" - : "=r" (rv) - : "0" (exchange_value), "r" (dest), "r" (compare_value) - : "memory"); - return rv; -} - -#endif // OS_CPU_LINUX_SPARC_ATOMIC_LINUX_SPARC_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/globals_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/globals_linux_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/globals_linux_sparc.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_GLOBALS_LINUX_SPARC_HPP -#define OS_CPU_LINUX_SPARC_GLOBALS_LINUX_SPARC_HPP - -// -// Sets the default values for platform dependent flags used by the -// runtime system. (see globals.hpp) -// - -define_pd_global(size_t, JVMInvokeMethodSlack, 12288); - -// Used on 64 bit platforms for UseCompressedOops base address -define_pd_global(size_t, HeapBaseMinAddress, CONST64(4)*G); - -#endif // OS_CPU_LINUX_SPARC_GLOBALS_LINUX_SPARC_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/linux_sparc.s b/src/hotspot/os_cpu/linux_sparc/linux_sparc.s deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/linux_sparc.s +++ /dev/null @@ -1,69 +0,0 @@ -# -# Copyright (c) 2005, 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. -# - - # Possibilities: - # -- membar - # -- CAS (SP + BIAS, G0, G0) - # -- wr %g0, %asi - - .globl SpinPause - .type SpinPause,@function - .align 32 -SpinPause: - retl - mov %g0, %o0 - - .globl _Copy_conjoint_jlongs_atomic - .type _Copy_conjoint_jlongs_atomic,@function -_Copy_conjoint_jlongs_atomic: - cmp %o0, %o1 - bleu 4f - sll %o2, 3, %o4 - ba 2f - 1: - subcc %o4, 8, %o4 - std %o2, [%o1] - add %o0, 8, %o0 - add %o1, 8, %o1 - 2: - bge,a 1b - ldd [%o0], %o2 - ba 5f - nop - 3: - std %o2, [%o1+%o4] - 4: - subcc %o4, 8, %o4 - bge,a 3b - ldd [%o0+%o4], %o2 - 5: - retl - nop - - - .globl _flush_reg_windows - .align 32 - _flush_reg_windows: - ta 0x03 - retl - mov %fp, %o0 diff --git a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP -#define OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP - -// Included in orderAccess.hpp header file. - -// Implementation of class OrderAccess. - -// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions -static inline void compiler_barrier() { - __asm__ volatile ("" : : : "memory"); -} - -// Assume TSO. - -inline void OrderAccess::loadload() { compiler_barrier(); } -inline void OrderAccess::storestore() { compiler_barrier(); } -inline void OrderAccess::loadstore() { compiler_barrier(); } -inline void OrderAccess::storeload() { fence(); } - -inline void OrderAccess::acquire() { compiler_barrier(); } -inline void OrderAccess::release() { compiler_barrier(); } - -inline void OrderAccess::fence() { - __asm__ volatile ("membar #StoreLoad" : : : "memory"); -} - -inline void OrderAccess::cross_modify_fence() { } - -#endif // OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/* - * Copyright (c) 1999, 2020, 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. - * - */ - -// no precompiled headers -#include "jvm.h" -#include "asm/macroAssembler.hpp" -#include "classfile/classLoader.hpp" -#include "classfile/systemDictionary.hpp" -#include "classfile/vmSymbols.hpp" -#include "code/codeCache.hpp" -#include "code/icBuffer.hpp" -#include "code/vtableStubs.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/allocation.inline.hpp" -#include "nativeInst_sparc.hpp" -#include "os_share_linux.hpp" -#include "prims/jniFastGetField.hpp" -#include "prims/jvm_misc.hpp" -#include "runtime/arguments.hpp" -#include "runtime/extendedPC.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/java.hpp" -#include "runtime/javaCalls.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/osThread.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/timer.hpp" -#include "utilities/debug.hpp" -#include "utilities/events.hpp" -#include "utilities/vmError.hpp" - -// Linux/Sparc has rather obscure naming of registers in sigcontext -// different between 32 and 64 bits -#define SIG_PC(x) ((x)->sigc_regs.tpc) -#define SIG_NPC(x) ((x)->sigc_regs.tnpc) -#define SIG_REGS(x) ((x)->sigc_regs) - -// those are to reference registers in sigcontext -enum { - CON_G0 = 0, - CON_G1, - CON_G2, - CON_G3, - CON_G4, - CON_G5, - CON_G6, - CON_G7, - CON_O0, - CON_O1, - CON_O2, - CON_O3, - CON_O4, - CON_O5, - CON_O6, - CON_O7, -}; - -// For Forte Analyzer AsyncGetCallTrace profiling support - thread is -// currently interrupted by SIGPROF. -// os::Solaris::fetch_frame_from_ucontext() tries to skip nested -// signal frames. Currently we don't do that on Linux, so it's the -// same as os::fetch_frame_from_context(). -ExtendedPC os::Linux::fetch_frame_from_ucontext(Thread* thread, - const ucontext_t* uc, - intptr_t** ret_sp, - intptr_t** ret_fp) { - assert(thread != NULL, "just checking"); - assert(ret_sp != NULL, "just checking"); - assert(ret_fp != NULL, "just checking"); - - return os::fetch_frame_from_context(uc, ret_sp, ret_fp); -} - -ExtendedPC os::fetch_frame_from_context(const void* ucVoid, - intptr_t** ret_sp, - intptr_t** ret_fp) { - const ucontext_t* uc = (const ucontext_t*) ucVoid; - ExtendedPC epc; - - if (uc != NULL) { - epc = ExtendedPC(os::Linux::ucontext_get_pc(uc)); - if (ret_sp) { - *ret_sp = os::Linux::ucontext_get_sp(uc); - } - if (ret_fp) { - *ret_fp = (intptr_t*)NULL; - } - } else { - // construct empty ExtendedPC for return value checking - epc = ExtendedPC(NULL); - if (ret_sp) { - *ret_sp = (intptr_t*) NULL; - } - if (ret_fp) { - *ret_fp = (intptr_t*) NULL; - } - } - - return epc; -} - -frame os::fetch_frame_from_context(const void* ucVoid) { - intptr_t* sp; - ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, NULL); - return frame(sp, frame::unpatchable, epc.pc()); -} - -frame os::get_sender_for_C_frame(frame* fr) { - return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc()); -} - -frame os::current_frame() { - intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()(); - frame myframe(sp, frame::unpatchable, - CAST_FROM_FN_PTR(address, os::current_frame)); - if (os::is_first_C_frame(&myframe)) { - // stack is not walkable - return frame(NULL, frame::unpatchable, NULL); - } else { - return os::get_sender_for_C_frame(&myframe); - } -} - -address os::current_stack_pointer() { - register void *sp __asm__ ("sp"); - return (address)sp; -} - -char* os::non_memory_address_word() { - // Must never look like an address returned by reserve_memory, - // even in its subfields (as defined by the CPU immediate fields, - // if the CPU splits constants across multiple instructions). - // On SPARC, 0 != %hi(any real address), because there is no - // allocation in the first 1Kb of the virtual address space. - return (char*) 0; -} - -void os::print_context(outputStream *st, const void *context) { - if (context == NULL) return; - - const ucontext_t* uc = (const ucontext_t*)context; - sigcontext* sc = (sigcontext*)context; - st->print_cr("Registers:"); - - st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT - " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, - SIG_REGS(sc).u_regs[CON_G1], - SIG_REGS(sc).u_regs[CON_G2], - SIG_REGS(sc).u_regs[CON_G3], - SIG_REGS(sc).u_regs[CON_G4]); - st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT - " G7=" INTPTR_FORMAT " Y=0x%x", - SIG_REGS(sc).u_regs[CON_G5], - SIG_REGS(sc).u_regs[CON_G6], - SIG_REGS(sc).u_regs[CON_G7], - SIG_REGS(sc).y); - st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT - " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, - SIG_REGS(sc).u_regs[CON_O0], - SIG_REGS(sc).u_regs[CON_O1], - SIG_REGS(sc).u_regs[CON_O2], - SIG_REGS(sc).u_regs[CON_O3]); - st->print_cr(" O4=" INTPTR_FORMAT " O5=" INTPTR_FORMAT - " O6=" INTPTR_FORMAT " O7=" INTPTR_FORMAT, - SIG_REGS(sc).u_regs[CON_O4], - SIG_REGS(sc).u_regs[CON_O5], - SIG_REGS(sc).u_regs[CON_O6], - SIG_REGS(sc).u_regs[CON_O7]); - - - intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); - st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT - " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT, - sp[L0->sp_offset_in_saved_window()], - sp[L1->sp_offset_in_saved_window()], - sp[L2->sp_offset_in_saved_window()], - sp[L3->sp_offset_in_saved_window()]); - st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT - " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT, - sp[L4->sp_offset_in_saved_window()], - sp[L5->sp_offset_in_saved_window()], - sp[L6->sp_offset_in_saved_window()], - sp[L7->sp_offset_in_saved_window()]); - st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT - " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT, - sp[I0->sp_offset_in_saved_window()], - sp[I1->sp_offset_in_saved_window()], - sp[I2->sp_offset_in_saved_window()], - sp[I3->sp_offset_in_saved_window()]); - st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT - " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT, - sp[I4->sp_offset_in_saved_window()], - sp[I5->sp_offset_in_saved_window()], - sp[I6->sp_offset_in_saved_window()], - sp[I7->sp_offset_in_saved_window()]); - - st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, - SIG_PC(sc), - SIG_NPC(sc)); - st->cr(); - st->cr(); - - st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", p2i(sp)); - print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - address pc = os::Linux::ucontext_get_pc(uc); - print_instructions(st, pc, sizeof(char)); - st->cr(); -} - - -void os::print_register_info(outputStream *st, const void *context) { - if (context == NULL) return; - - const ucontext_t *uc = (const ucontext_t*)context; - const sigcontext* sc = (const sigcontext*)context; - intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - st->print("G1="); print_location(st, SIG_REGS(sc).u_regs[CON_G1]); - st->print("G2="); print_location(st, SIG_REGS(sc).u_regs[CON_G2]); - st->print("G3="); print_location(st, SIG_REGS(sc).u_regs[CON_G3]); - st->print("G4="); print_location(st, SIG_REGS(sc).u_regs[CON_G4]); - st->print("G5="); print_location(st, SIG_REGS(sc).u_regs[CON_G5]); - st->print("G6="); print_location(st, SIG_REGS(sc).u_regs[CON_G6]); - st->print("G7="); print_location(st, SIG_REGS(sc).u_regs[CON_G7]); - st->cr(); - - st->print("O0="); print_location(st, SIG_REGS(sc).u_regs[CON_O0]); - st->print("O1="); print_location(st, SIG_REGS(sc).u_regs[CON_O1]); - st->print("O2="); print_location(st, SIG_REGS(sc).u_regs[CON_O2]); - st->print("O3="); print_location(st, SIG_REGS(sc).u_regs[CON_O3]); - st->print("O4="); print_location(st, SIG_REGS(sc).u_regs[CON_O4]); - st->print("O5="); print_location(st, SIG_REGS(sc).u_regs[CON_O5]); - st->print("O6="); print_location(st, SIG_REGS(sc).u_regs[CON_O6]); - st->print("O7="); print_location(st, SIG_REGS(sc).u_regs[CON_O7]); - st->cr(); - - st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]); - st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]); - st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]); - st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]); - st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]); - st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]); - st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]); - st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]); - st->cr(); - - st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]); - st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]); - st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]); - st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]); - st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]); - st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]); - st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]); - st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]); - st->cr(); -} - - -address os::Linux::ucontext_get_pc(const ucontext_t* uc) { - return (address) SIG_PC((sigcontext*)uc); -} - -void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) { - sigcontext* ctx = (sigcontext*) uc; - SIG_PC(ctx) = (intptr_t)pc; - SIG_NPC(ctx) = (intptr_t)(pc+4); -} - -intptr_t* os::Linux::ucontext_get_sp(const ucontext_t *uc) { - return (intptr_t*) - ((intptr_t)SIG_REGS((sigcontext*)uc).u_regs[CON_O6] + STACK_BIAS); -} - -// not used on Sparc -intptr_t* os::Linux::ucontext_get_fp(const ucontext_t *uc) { - ShouldNotReachHere(); - return NULL; -} - -// Utility functions - -inline static bool checkPrefetch(sigcontext* uc, address pc) { - if (StubRoutines::is_safefetch_fault(pc)) { - os::Linux::ucontext_set_pc((ucontext_t*)uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return true; - } - return false; -} - -inline static bool checkOverflow(sigcontext* uc, - address pc, - address addr, - JavaThread* thread, - address* stub) { - // check if fault address is within thread stack - if (thread->is_in_full_stack(addr)) { - // stack overflow - if (thread->in_stack_yellow_reserved_zone(addr)) { - thread->disable_stack_yellow_reserved_zone(); - if (thread->thread_state() == _thread_in_Java) { - // Throw a stack overflow exception. Guard pages will be reenabled - // while unwinding the stack. - *stub = - SharedRuntime::continuation_for_implicit_exception(thread, - pc, - SharedRuntime::STACK_OVERFLOW); - } else { - // Thread was in the vm or native code. Return and try to finish. - return true; - } - } else if (thread->in_stack_red_zone(addr)) { - // Fatal red zone violation. Disable the guard pages and fall through - // to handle_unexpected_exception way down below. - thread->disable_stack_red_zone(); - tty->print_raw_cr("An irrecoverable stack overflow has occurred."); - - // This is a likely cause, but hard to verify. Let's just print - // it as a hint. - tty->print_raw_cr("Please check if any of your loaded .so files has " - "enabled executable stack (see man page execstack(8))"); - } else { - // Accessing stack address below sp may cause SEGV if current - // thread has MAP_GROWSDOWN stack. This should only happen when - // current thread was created by user code with MAP_GROWSDOWN flag - // and then attached to VM. See notes in os_linux.cpp. - if (thread->osthread()->expanding_stack() == 0) { - thread->osthread()->set_expanding_stack(); - if (os::Linux::manually_expand_stack(thread, addr)) { - thread->osthread()->clear_expanding_stack(); - return true; - } - thread->osthread()->clear_expanding_stack(); - } else { - fatal("recursive segv. expanding stack."); - } - } - } - return false; -} - -inline static bool checkPollingPage(address pc, address fault, address* stub) { - if (SafepointMechanism::is_poll_address(fault)) { - *stub = SharedRuntime::get_poll_stub(pc); - return true; - } - return false; -} - -inline static bool checkByteBuffer(address pc, address npc, JavaThread * thread, address* stub) { - // BugId 4454115: A read from a MappedByteBuffer can fault - // here if the underlying file has been truncated. - // Do not crash the VM in such a case. - CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - CompiledMethod* nm = cb->as_compiled_method_or_null(); - bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); - if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) { - if (is_unsafe_arraycopy) { - npc = UnsafeCopyMemory::page_error_continue_pc(pc); - } - *stub = SharedRuntime::handle_unsafe_access(thread, npc); - return true; - } - return false; -} - -inline static bool checkVerifyOops(address pc, address fault, address* stub) { - if (pc >= MacroAssembler::_verify_oop_implicit_branch[0] - && pc < MacroAssembler::_verify_oop_implicit_branch[1] ) { - *stub = MacroAssembler::_verify_oop_implicit_branch[2]; - warning("fixed up memory fault in +VerifyOops at address " - INTPTR_FORMAT, p2i(fault)); - return true; - } - return false; -} - -inline static bool checkFPFault(address pc, int code, - JavaThread* thread, address* stub) { - if (code == FPE_INTDIV || code == FPE_FLTDIV) { - *stub = - SharedRuntime:: - continuation_for_implicit_exception(thread, - pc, - SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - return true; - } - return false; -} - -inline static bool checkNullPointer(address pc, void* fault, - JavaThread* thread, address* stub) { - if (MacroAssembler::uses_implicit_null_check(fault)) { - // Determination of interpreter/vtable stub/compiled code null - // exception - *stub = - SharedRuntime:: - continuation_for_implicit_exception(thread, pc, - SharedRuntime::IMPLICIT_NULL); - return true; - } - return false; -} - -inline static bool checkFastJNIAccess(address pc, address* stub) { - address addr = JNI_FastGetField::find_slowcase_pc(pc); - if (addr != (address)-1) { - *stub = addr; - return true; - } - return false; -} - -inline static bool checkZombie(sigcontext* uc, address* pc, address* stub) { - if (nativeInstruction_at(*pc)->is_zombie()) { - // zombie method (ld [%g0],%o7 instruction) - *stub = SharedRuntime::get_handle_wrong_method_stub(); - - // At the stub it needs to look like a call from the caller of this - // method (not a call from the segv site). - *pc = (address)SIG_REGS(uc).u_regs[CON_O7]; - return true; - } - return false; -} - -inline static bool checkICMiss(sigcontext* uc, address* pc, address* stub) { -#ifdef COMPILER2 - if (nativeInstruction_at(*pc)->is_ic_miss_trap()) { -#ifdef ASSERT -#ifdef TIERED - CodeBlob* cb = CodeCache::find_blob_unsafe(*pc); - assert(cb->is_compiled_by_c2(), "Wrong compiler"); -#endif // TIERED -#endif // ASSERT - // Inline cache missed and user trap "Tne G0+ST_RESERVED_FOR_USER_0+2" taken. - *stub = SharedRuntime::get_ic_miss_stub(); - // At the stub it needs to look like a call from the caller of this - // method (not a call from the segv site). - *pc = (address)SIG_REGS(uc).u_regs[CON_O7]; - return true; - } -#endif // COMPILER2 - return false; -} - -extern "C" JNIEXPORT int -JVM_handle_linux_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - // in fact this isn't ucontext_t* at all, but struct sigcontext* - // but Linux porting layer uses ucontext_t, so to minimize code change - // we cast as needed - ucontext_t* ucFake = (ucontext_t*) ucVoid; - sigcontext* uc = (sigcontext*)ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away - // (no destructors can be run) - os::ThreadCrashProtection::check_crash_protection(sig, t); - - SignalHandlerMark shm(t); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (os::Linux::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - -#ifdef CAN_SHOW_REGISTERS_ON_ASSERT - if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { - if (handle_assert_poison_fault(ucVoid, info->si_addr)) { - return 1; - } - } -#endif - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (os::Linux::signal_handlers_are_installed) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = (JavaThread*)t; - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } - - // decide if this trap can be handled by a stub - address stub = NULL; - address pc = NULL; - address npc = NULL; - - //%note os_trap_1 - if (info != NULL && uc != NULL && thread != NULL) { - pc = address(SIG_PC(uc)); - npc = address(SIG_NPC(uc)); - - if (checkPrefetch(uc, pc)) { - return 1; - } - - // Handle ALL stack overflow variations here - if (sig == SIGSEGV) { - if (checkOverflow(uc, pc, (address)info->si_addr, thread, &stub)) { - return 1; - } - } - - if (sig == SIGBUS && - (thread->thread_state() == _thread_in_vm || - thread->thread_state() == _thread_in_native) && - thread->doing_unsafe_access()) { - if (UnsafeCopyMemory::contains_pc(pc)) { - npc = UnsafeCopyMemory::page_error_continue_pc(pc); - } - stub = SharedRuntime::handle_unsafe_access(thread, npc); - } - - if (thread->thread_state() == _thread_in_Java) { - do { - // Java thread running in Java code => find exception handler if any - // a fault inside compiled code, the interpreter, or a stub - - if ((sig == SIGSEGV) && checkPollingPage(pc, (address)info->si_addr, &stub)) { - break; - } - - if ((sig == SIGBUS) && checkByteBuffer(pc, npc, thread, &stub)) { - break; - } - - if ((sig == SIGSEGV || sig == SIGBUS) && - checkVerifyOops(pc, (address)info->si_addr, &stub)) { - break; - } - - if ((sig == SIGSEGV) && checkZombie(uc, &pc, &stub)) { - break; - } - - if ((sig == SIGILL) && checkICMiss(uc, &pc, &stub)) { - break; - } - - if ((sig == SIGFPE) && checkFPFault(pc, info->si_code, thread, &stub)) { - break; - } - - if ((sig == SIGSEGV) && - checkNullPointer(pc, info->si_addr, thread, &stub)) { - break; - } - } while (0); - - // jni_fast_GetField can trap at certain pc's if a GC kicks in - // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { - checkFastJNIAccess(pc, &stub); - } - } - - if (stub != NULL) { - // save all thread context in case we need to restore it - thread->set_saved_exception_pc(pc); - thread->set_saved_exception_npc(npc); - os::Linux::ucontext_set_pc((ucontext_t*)uc, stub); - return true; - } - } - - // signal-chaining - if (os::Linux::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc((const ucontext_t*)uc); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); - return false; -} - -void os::Linux::init_thread_fpu_state(void) { - // Nothing to do -} - -int os::Linux::get_fpu_control_word() { - return 0; -} - -void os::Linux::set_fpu_control_word(int fpu) { - // nothing -} - -bool os::is_allocatable(size_t bytes) { - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// thread stack - -// Minimum usable stack sizes required to get to user code. Space for -// HotSpot guard pages is added later. -size_t os::Posix::_compiler_thread_min_stack_allowed = 64 * K; -size_t os::Posix::_java_thread_min_stack_allowed = 64 * K; -size_t os::Posix::_vm_internal_thread_min_stack_allowed = 128 * K; - -// return default stack size for thr_type -size_t os::Posix::default_stack_size(os::ThreadType thr_type) { - // default stack size (compiler thread needs larger stack) - size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M); - return s; -} - -#ifndef PRODUCT -void os::verify_stack_alignment() { -} -#endif - -int os::extra_bang_size_in_bytes() { - // SPARC does not require the additional stack bang. - return 0; -} diff --git a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_OS_LINUX_SPARC_HPP -#define OS_CPU_LINUX_SPARC_OS_LINUX_SPARC_HPP - - // - // NOTE: we are back in class os here, not Linux - // - static int32_t (*atomic_xchg_func) (int32_t, volatile int32_t*); - static int32_t (*atomic_cmpxchg_func) (int32_t, volatile int32_t*, int32_t); - static int64_t (*atomic_cmpxchg_long_func)(int64_t, volatile int64_t*, int64_t); - static int32_t (*atomic_add_func) (int32_t, volatile int32_t*); - - static int32_t atomic_xchg_bootstrap (int32_t, volatile int32_t*); - static int32_t atomic_cmpxchg_bootstrap (int32_t, volatile int32_t*, int32_t); - static int64_t atomic_cmpxchg_long_bootstrap(int64_t, volatile int64_t*, int64_t); - static int32_t atomic_add_bootstrap (int32_t, volatile int32_t*); - - static void setup_fpu() {} - - static bool is_allocatable(size_t bytes); - - // Used to register dynamic code cache area with the OS - // Note: Currently only used in 64 bit Windows implementations - static bool register_code_area(char *low, char *high) { return true; } - -#endif // OS_CPU_LINUX_SPARC_OS_LINUX_SPARC_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/prefetch_linux_sparc.inline.hpp b/src/hotspot/os_cpu/linux_sparc/prefetch_linux_sparc.inline.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/prefetch_linux_sparc.inline.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_PREFETCH_LINUX_SPARC_INLINE_HPP -#define OS_CPU_LINUX_SPARC_PREFETCH_LINUX_SPARC_INLINE_HPP - -#include "runtime/prefetch.hpp" - -inline void Prefetch::read(void *loc, intx interval) { - __asm__ volatile("prefetch [%0+%1], 0" : : "r" (loc), "r" (interval) : "memory" ); -} - -inline void Prefetch::write(void *loc, intx interval) { - __asm__ volatile("prefetch [%0+%1], 2" : : "r" (loc), "r" (interval) : "memory" ); -} - -#endif // OS_CPU_LINUX_SPARC_PREFETCH_LINUX_SPARC_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2003, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "memory/metaspaceShared.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/thread.inline.hpp" - -frame JavaThread::pd_last_frame() { - assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); - assert(_anchor.walkable(), "thread has not dumped its register windows yet"); - - assert(_anchor.last_Java_pc() != NULL, "Ack no pc!"); - return frame(last_Java_sp(), frame::unpatchable, _anchor.last_Java_pc()); -} - -bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { - ucontext_t* uc = (ucontext_t*) ucontext; - *fr_addr = frame((intptr_t*)uc->uc_mcontext.mc_i7, frame::unpatchable, - (address)uc->uc_mcontext.mc_gregs[MC_PC]); - return true; -} - -// For Forte Analyzer AsyncGetCallTrace profiling support - thread is -// currently interrupted by SIGPROF -bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, - void* ucontext, - bool isInJava) { - assert(Thread::current() == this, "caller must be current thread"); - assert(this->is_Java_thread(), "must be JavaThread"); - - JavaThread* jt = (JavaThread *)this; - - if (!isInJava) { - // make_walkable flushes register windows and grabs last_Java_pc - // which can not be done if the ucontext sp matches last_Java_sp - // stack walking utilities assume last_Java_pc set if marked flushed - jt->frame_anchor()->make_walkable(jt); - } - - // If we have a walkable last_Java_frame, then we should use it - // even if isInJava == true. It should be more reliable than - // ucontext info. - if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { - *fr_addr = jt->pd_last_frame(); - return true; - } - - ucontext_t* uc = (ucontext_t*) ucontext; - - // At this point, we don't have a walkable last_Java_frame, so - // we try to glean some information out of the ucontext. - intptr_t* ret_sp; - ExtendedPC addr = - os::fetch_frame_from_context(uc, &ret_sp, - NULL /* ret_fp only used on X86 */); - if (addr.pc() == NULL || ret_sp == NULL) { - // ucontext wasn't useful - return false; - } - - if (MetaspaceShared::is_in_trampoline_frame(addr.pc())) { - // In the middle of a trampoline call. Bail out for safety. - // This happens rarely so shouldn't affect profiling. - return false; - } - - // we were running Java code when SIGPROF came in - if (isInJava) { - // If we have a last_Java_sp, then the SIGPROF signal caught us - // right when we were transitioning from _thread_in_Java to a new - // JavaThreadState. We use last_Java_sp instead of the sp from - // the ucontext since it should be more reliable. - if (jt->has_last_Java_frame()) { - ret_sp = jt->last_Java_sp(); - } - // Implied else: we don't have a last_Java_sp so we use what we - // got from the ucontext. - - frame ret_frame(ret_sp, frame::unpatchable, addr.pc()); - if (!ret_frame.safe_for_sender(jt)) { - // nothing else to try if the frame isn't good - return false; - } - *fr_addr = ret_frame; - return true; - } - - // At this point, we know we weren't running Java code. We might - // have a last_Java_sp, but we don't have a walkable frame. - // However, we might still be able to construct something useful - // if the thread was running native code. - if (jt->has_last_Java_frame()) { - assert(!jt->frame_anchor()->walkable(), "case covered above"); - - if (jt->thread_state() == _thread_in_native) { - frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc()); - if (!ret_frame.safe_for_sender(jt)) { - // nothing else to try if the frame isn't good - return false; - } - *fr_addr = ret_frame; - return true; - } - } - - // nothing else to try - return false; -} - -void JavaThread::cache_global_variables() { } - diff --git a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP -#define OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP - -private: - - void pd_initialize() { - _anchor.clear(); - _base_of_stack_pointer = NULL; - } - - frame pd_last_frame(); - - // Sometimes the trap handler needs to record both PC and NPC. - // This is a SPARC-specific companion to Thread::set_saved_exception_pc. - address _saved_exception_npc; - - // In polling_page_safepoint_handler_blob(s) we have to tail call other - // blobs without blowing any registers. A tail call requires some - // register to jump with and we can't blow any registers, so it must - // be restored in the delay slot. 'restore' cannot be used as it - // will chop the heads off of 64-bit %o registers in the 32-bit - // build. Instead we reload the registers using G2_thread and this - // location. Must be 64bits in the 32-bit LION build. - jdouble _o_reg_temps[6]; - - // a stack pointer older than any java frame stack pointer. It is - // used to validate stack pointers in frame::next_younger_sp (it - // provides the upper bound in the range check). This is necessary - // on Solaris/SPARC since the ucontext passed to a signal handler is - // sometimes corrupt and we need a way to check the extracted sp. - intptr_t* _base_of_stack_pointer; - -public: - - static int o_reg_temps_offset_in_bytes() { return offset_of(JavaThread, _o_reg_temps); } - -#ifndef _LP64 - address o_reg_temps(int i) { return (address)&_o_reg_temps[i]; } -#endif - - static ByteSize saved_exception_npc_offset() { return byte_offset_of(JavaThread,_saved_exception_npc); } - - address saved_exception_npc() { return _saved_exception_npc; } - void set_saved_exception_npc(address a) { _saved_exception_npc = a; } - - -public: - - intptr_t* base_of_stack_pointer() { return _base_of_stack_pointer; } - - void set_base_of_stack_pointer(intptr_t* base_sp) { - _base_of_stack_pointer = base_sp; - } - - void record_base_of_stack_pointer() { - intptr_t *sp = (intptr_t *)(((intptr_t)StubRoutines::Sparc::flush_callers_register_windows_func()())); - intptr_t *ysp; - while((ysp = (intptr_t*)sp[FP->sp_offset_in_saved_window()]) != NULL) { - sp = (intptr_t *)((intptr_t)ysp + STACK_BIAS); - } - _base_of_stack_pointer = sp; - } - - bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava); - - bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava); - - // These routines are only used on cpu architectures that - // have separate register stacks (Itanium). - static bool register_stack_overflow() { return false; } - static void enable_register_stack_guard() {} - static void disable_register_stack_guard() {} - -#endif // OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/vmStructs_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/vmStructs_linux_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/vmStructs_linux_sparc.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_CPU_LINUX_SPARC_VMSTRUCTS_LINUX_SPARC_HPP -#define OS_CPU_LINUX_SPARC_VMSTRUCTS_LINUX_SPARC_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_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) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) - - -#define VM_TYPES_OS_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) \ - \ - /**********************/ \ - /* POSIX Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) - - -#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ - \ - /************************/ \ - /* JavaThread constants */ \ - /************************/ \ - \ - declare_constant(JavaFrameAnchor::flushed) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#endif // OS_CPU_LINUX_SPARC_VMSTRUCTS_LINUX_SPARC_HPP diff --git a/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2006, 2019, 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. - * - */ - -#include "logging/log.hpp" -#include "precompiled.hpp" -#include "runtime/os.hpp" -#include "runtime/vm_version.hpp" - - -#define CPUINFO_LINE_SIZE 1024 - - -class CPUinfo { -public: - CPUinfo(const char* field) : _string(NULL) { - - char line[CPUINFO_LINE_SIZE]; - FILE* fp = fopen("/proc/cpuinfo", "r"); - - if (fp != NULL) { - while (fgets(line, sizeof(line), fp) != NULL) { - assert(strlen(line) < sizeof(line) - 1, - "buffer too small (%d)", CPUINFO_LINE_SIZE); - - const char* vstr = match_field(line, field); - - if (vstr != NULL) { - // We have a matching line and a valid starting point to the value of - // the field, copy the string for keeps. - _string = strdup(vstr); - break; - } - } - fclose(fp); - } - } - - ~CPUinfo() { free((void*)_string); } - - const char* value() const { return _string; } - - bool valid() const { return _string != NULL; } - - bool match(const char* s) const { - return valid() ? strcmp(_string, s) == 0 : false; - } - -private: - const char* _string; - - const char* match_field(char line[CPUINFO_LINE_SIZE], const char* field); - const char* match_alo(const char* text, const char* exp); - const char* match_seq(const char* text, const char* seq); -}; - -/* Given a line of text read from /proc/cpuinfo, determine if the property header - * matches the field specified, according to the following regexp: ""\W+:\W+ - * - * If we have a matching expression, return a pointer to the first character after - * the matching pattern, i.e. the "value", otherwise return NULL. - */ -const char* CPUinfo::match_field(char line[CPUINFO_LINE_SIZE], const char* field) { - return match_alo(match_seq(match_alo(match_seq(line, field), "\t "), ":"), "\t "); -} - -/* Match a sequence of at-least-one character in the string expression (exp) to - * the text input. - */ -const char* CPUinfo::match_alo(const char* text, const char* exp) { - if (text == NULL) return NULL; - - const char* chp; - - for (chp = &text[0]; *chp != '\0'; chp++) { - if (strchr(exp, *chp) == NULL) break; - } - - return text < chp ? chp : NULL; -} - -/* Match an exact sequence of characters as specified by the string expression - * (seq) to the text input. - */ -const char* CPUinfo::match_seq(const char* text, const char* seq) { - if (text == NULL) return NULL; - - while (*seq != '\0') { - if (*seq != *text++) break; else seq++; - } - - return *seq == '\0' ? text : NULL; -} - - -typedef struct { - const uint32_t hash; - bool seen; - const char* const name; - const uint64_t mask; -} FeatureEntry; - - -static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]); - - -void VM_Version::platform_features() { - - // Some of the features reported via "cpucaps", such as; 'flush', 'stbar', - // 'swap', 'muldiv', 'ultra3', 'blkinit', 'n2', 'mul32', 'div32', 'fsmuld' - // and 'v8plus', are either SPARC V8, supported by all HW or simply nonsense - // (the 'ultra3' "property"). - // - // Entries marked as 'NYI' are not yet supported via "cpucaps" but are - // expected to have the names used in the table below (these are SPARC M7 - // features or more recent). - // - // NOTE: Table sorted on lookup/hash ID. - - static FeatureEntry s_feature_tbl[] = { - { 0x006f, false, "v9", ISA_v9_msk }, // Mandatory - { 0x00a6, false, "md5", ISA_md5_msk }, - { 0x00ce, false, "adi", ISA_adi_msk }, // NYI - { 0x00d7, false, "ima", ISA_ima_msk }, - { 0x00d9, false, "aes", ISA_aes_msk }, - { 0x00db, false, "hpc", ISA_hpc_msk }, - { 0x00dc, false, "des", ISA_des_msk }, - { 0x00ed, false, "sha1", ISA_sha1_msk }, - { 0x00f2, false, "vis", ISA_vis1_msk }, - { 0x0104, false, "vis2", ISA_vis2_msk }, - { 0x0105, false, "vis3", ISA_vis3_msk }, - { 0x0114, false, "sha512", ISA_sha512_msk }, - { 0x0119, false, "sha256", ISA_sha256_msk }, - { 0x011a, false, "fmaf", ISA_fmaf_msk }, - { 0x0132, false, "popc", ISA_popc_msk }, - { 0x0140, false, "crc32c", ISA_crc32c_msk }, - { 0x0147, false, "vis3b", ISA_vis3b_msk }, // NYI - { 0x017e, false, "pause", ISA_pause_msk }, - { 0x0182, false, "mwait", ISA_mwait_msk }, // NYI - { 0x018b, false, "mpmul", ISA_mpmul_msk }, - { 0x018e, false, "sparc5", ISA_sparc5_msk }, // NYI - { 0x01a9, false, "cbcond", ISA_cbcond_msk }, - { 0x01c3, false, "vamask", ISA_vamask_msk }, // NYI - { 0x01ca, false, "kasumi", ISA_kasumi_msk }, - { 0x01e3, false, "xmpmul", ISA_xmpmul_msk }, // NYI - { 0x022c, false, "montmul", ISA_mont_msk }, - { 0x0234, false, "montsqr", ISA_mont_msk }, - { 0x0238, false, "camellia", ISA_camellia_msk }, - { 0x024a, false, "ASIBlkInit", ISA_blk_init_msk }, - { 0x0284, false, "xmontmul", ISA_xmont_msk }, // NYI - { 0x02e6, false, "pause_nsec", ISA_pause_nsec_msk }, // NYI - - { 0x0000, false, NULL, 0 } - }; - - CPUinfo caps("cpucaps"); // Read "cpucaps" from /proc/cpuinfo. - - assert(caps.valid(), "must be"); - - _features = parse_features(s_feature_tbl, caps.value()); - - assert(has_v9(), "must be"); // Basic SPARC-V9 required (V8 not supported). - - CPUinfo type("type"); - - bool is_sun4v = type.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+ - bool is_sun4u = type.match("sun4u"); // All other Fujitsu - - uint64_t synthetic = 0; - - if (is_sun4v) { - // Indirect and direct branches are equally fast. - synthetic = CPU_fast_ind_br_msk; - // Fast IDIV, BIS and LD available on Niagara Plus. - if (has_vis2()) { - synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk); - // ...on Core C4 however, we prefer not to use BIS. - if (!has_sparc5()) { - synthetic |= CPU_fast_bis_msk; - } - } - // Niagara Core C3 supports fast RDPC and block zeroing. - if (has_ima()) { - synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk); - } - // Niagara Core C3 and C4 have slow CMOVE. - if (!has_ima()) { - synthetic |= CPU_fast_cmove_msk; - } - } else if (is_sun4u) { - // SPARC64 only have fast IDIV and RDPC. - synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk); - } else { - log_info(os, cpu)("Unable to derive CPU features: %s", type.value()); - } - - _features += synthetic; // Including CPU derived/synthetic features. -} - - -//////////////////////////////////////////////////////////////////////////////// - -static uint32_t uhash32(const char name[]); - -static void update_table(FeatureEntry feature_tbl[], uint32_t hv, - const char* ch1p, - const char* endp); - -/* Given a feature table, parse the input text holding the string value of - * 'cpucaps' as reported by '/proc/cpuinfo', in order to complete the table - * with information on each admissible feature (whether present or not). - * - * Return the composite bit-mask representing the features found. - */ -static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]) { - log_info(os, cpu)("Parse CPU features: %s\n", input); - -#ifdef ASSERT - // Verify that hash value entries in the table are unique and ordered. - - uint32_t prev = 0; - - for (uint k = 0; feature_tbl[k].name != NULL; k++) { - feature_tbl[k].seen = false; - - assert(feature_tbl[k].hash == uhash32(feature_tbl[k].name), - "feature '%s' has mismatching hash 0x%08x (expected 0x%08x).\n", - feature_tbl[k].name, - feature_tbl[k].hash, - uhash32(feature_tbl[k].name)); - - assert(prev < feature_tbl[k].hash, - "feature '%s' has invalid hash 0x%08x (previous is 0x%08x).\n", - feature_tbl[k].name, - feature_tbl[k].hash, - prev); - - prev = feature_tbl[k].hash; - } -#endif - // Identify features from the input, consisting of a string with features - // separated by commas (or whitespace), e.g. "flush,muldiv,v9,mul32,div32, - // v8plus,popc,vis". - - uint32_t hv = 0; - const char* ch1p = &input[0]; - uint i = 0; - - do { - char ch = input[i]; - - if (isalnum(ch) || ch == '_') { - hv += (ch - 32u); - } - else if (isspace(ch) || ch == ',' || ch == '\0') { // end-of-token - if (ch1p < &input[i]) { - update_table(feature_tbl, hv, ch1p, &input[i]); - } - ch1p = &input[i + 1]; hv = 0; - } else { - // Handle non-accepted input robustly. - log_info(os, cpu)("Bad token in feature string: '%c' (0x%02x).\n", ch, ch); - ch1p = &input[i + 1]; hv = 0; - } - } - while (input[i++] != '\0'); - - // Compute actual bit-mask representation. - - uint64_t mask = 0; - - for (uint k = 0; feature_tbl[k].name != NULL; k++) { - mask |= feature_tbl[k].seen ? feature_tbl[k].mask : 0; - } - - return mask; -} - -static uint32_t uhash32(const char name[]) { - uint32_t hv = 0; - - for (uint i = 0; name[i] != '\0'; i++) { - hv += (name[i] - 32u); - } - - return hv; -} - -static bool verify_match(const char name[], const char* ch1p, const char* endp); - -static void update_table(FeatureEntry feature_tbl[], uint32_t hv, const char* ch1p, const char* endp) { - assert(ch1p < endp, "at least one character"); - - // Look for a hash value in the table. Since this table is a small one (and - // is expected to stay small), we use a simple linear search (iff the table - // grows large, we may consider to adopt a binary ditto, or a perfect hash). - - for (uint k = 0; feature_tbl[k].name != NULL; k++) { - uint32_t hash = feature_tbl[k].hash; - - if (hash < hv) continue; - - if (hash == hv) { - const char* name = feature_tbl[k].name; - - if (verify_match(name, ch1p, endp)) { - feature_tbl[k].seen = true; - break; - } - } - - // Either a non-matching feature (when hash == hv) or hash > hv. In either - // case we break out of the loop and terminate the search (note that the - // table is assumed to be uniquely sorted on the hash). - - break; - } -} - -static bool verify_match(const char name[], const char* ch1p, const char* endp) { - size_t len = strlen(name); - - if (len != static_cast(endp - ch1p)) { - return false; - } - - for (uint i = 0; ch1p + i < endp; i++) { - if (name[i] != ch1p[i]) return false; - } - - return true; -} diff --git a/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp b/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp --- a/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp +++ b/src/hotspot/os_cpu/linux_x86/bytes_linux_x86.inline.hpp @@ -63,18 +63,7 @@ #ifdef AMD64 inline u8 Bytes::swap_u8(u8 x) { -#ifdef SPARC_WORKS - // workaround for SunStudio12 CR6615391 - __asm__ __volatile__ ( - "bswapq %0" - :"=r" (x) // output : register 0 => x - :"0" (x) // input : x => register 0 - :"0" // clobbered register - ); - return x; -#else return bswap_64(x); -#endif } #else // Helper function for swap_u8 diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -95,13 +95,7 @@ #endif // AMD64 address os::current_stack_pointer() { -#ifdef SPARC_WORKS - void *esp; - __asm__("mov %%" SPELL_REG_SP ", %0":"=r"(esp)); - return (address) ((char*)esp + sizeof(long)*2); -#else return (address)__builtin_frame_address(0); -#endif } char* os::non_memory_address_word() { @@ -224,10 +218,7 @@ } intptr_t* _get_previous_fp() { -#ifdef SPARC_WORKS - intptr_t **ebp; - __asm__("mov %%" SPELL_REG_FP ", %0":"=r"(ebp)); -#elif defined(__clang__) +#if defined(__clang__) intptr_t **ebp; __asm__ __volatile__ ("mov %%" SPELL_REG_FP ", %0":"=r"(ebp):); #else diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -86,14 +86,8 @@ // Must never look like an address returned by reserve_memory, // even in its subfields (as defined by the CPU immediate fields, // if the CPU splits constants across multiple instructions). -#ifdef SPARC - // On SPARC, 0 != %hi(any real address), because there is no - // allocation in the first 1Kb of the virtual address space. - return (char *) 0; -#else // This is the value for x86; works pretty well for PPC too. return (char *) -1; -#endif // SPARC } address os::Linux::ucontext_get_pc(const ucontext_t* uc) { diff --git a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP - -// Implementation of class atomic - -// Implement ADD using a CAS loop. -template -struct Atomic::PlatformAdd { - template - inline D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const { - D old_value = *dest; - while (true) { - D new_value = old_value + add_value; - D result = cmpxchg(dest, old_value, new_value); - if (result == old_value) break; - old_value = result; - } - return old_value + add_value; - } - - template - inline D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { - return add_and_fetch(dest, add_value, order) - add_value; - } -}; - -template<> -template -inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(T)); - __asm__ volatile ( "swap [%2],%0" - : "=r" (exchange_value) - : "0" (exchange_value), "r" (dest) - : "memory"); - return exchange_value; -} - -template<> -template -inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - T old_value = *dest; - while (true) { - T result = cmpxchg(dest, old_value, exchange_value); - if (result == old_value) break; - old_value = result; - } - return old_value; -} - -// No direct support for cmpxchg of bytes; emulate using int. -template<> -struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {}; - -template<> -template -inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(T)); - T rv; - __asm__ volatile( - " cas [%2], %3, %0" - : "=r" (rv) - : "0" (exchange_value), "r" (dest), "r" (compare_value) - : "memory"); - return rv; -} - -template<> -template -inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - T rv; - __asm__ volatile( - " casx [%2], %3, %0" - : "=r" (rv) - : "0" (exchange_value), "r" (dest), "r" (compare_value) - : "memory"); - return rv; -} - -#endif // OS_CPU_SOLARIS_SPARC_ATOMIC_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/count_trailing_zeros_solaris_sparc.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2017, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP - -#include "utilities/globalDefinitions.hpp" - -inline unsigned count_trailing_zeros(uintx x) { - assert(x != 0, "precondition"); - // Reduce to mask with ones in all positions below the least - // significant set bit of x, and zeros otherwise. - uintx rx = (x - 1) & ~x; // sub x, 1, rx; andn rx, x, rx; - // Then count the set bits in the reduction. - uintx result; - __asm__(" popc %1, %0\n\t" : "=r" (result) : "r" (rx)); - return result; -} - -#endif // OS_CPU_SOLARIS_SPARC_COUNT_TRAILING_ZEROS_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/globals_solaris_sparc.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP - -// -// Sets the default values for platform dependent flags used by the runtime system. -// (see globals.hpp) -// - -define_pd_global(size_t, JVMInvokeMethodSlack, 12288); - -// Used on 64 bit platforms for UseCompressedOops base address -// use 6G as default base address because by default the OS maps the application -// to 4G on Solaris-Sparc. This leaves at least 2G for the native heap. -define_pd_global(size_t, HeapBaseMinAddress, CONST64(6)*G); - - - -#endif // OS_CPU_SOLARIS_SPARC_GLOBALS_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP - -// Included in orderAccess.hpp header file. - -// Compiler version last used for testing: solaris studio 12u3 -// Please update this information when this file changes - -// Implementation of class OrderAccess. - -// Assume TSO. - -// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions -inline void compiler_barrier() { - __asm__ volatile ("" : : : "memory"); -} - -inline void OrderAccess::loadload() { compiler_barrier(); } -inline void OrderAccess::storestore() { compiler_barrier(); } -inline void OrderAccess::loadstore() { compiler_barrier(); } -inline void OrderAccess::storeload() { fence(); } - -inline void OrderAccess::acquire() { compiler_barrier(); } -inline void OrderAccess::release() { compiler_barrier(); } - -inline void OrderAccess::fence() { - __asm__ volatile ("membar #StoreLoad" : : : "memory"); -} - -inline void OrderAccess::cross_modify_fence() { } - -#endif // OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Copyright (c) 1999, 2020, 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. - * - */ - -// no precompiled headers -#include "jvm.h" -#include "asm/macroAssembler.hpp" -#include "macroAssembler_sparc.hpp" -#include "classfile/classLoader.hpp" -#include "classfile/systemDictionary.hpp" -#include "classfile/vmSymbols.hpp" -#include "code/codeCache.hpp" -#include "code/icBuffer.hpp" -#include "code/vtableStubs.hpp" -#include "interpreter/interpreter.hpp" -#include "memory/allocation.inline.hpp" -#include "nativeInst_sparc.hpp" -#include "os_share_solaris.hpp" -#include "prims/jniFastGetField.hpp" -#include "prims/jvm_misc.hpp" -#include "runtime/arguments.hpp" -#include "runtime/extendedPC.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/java.hpp" -#include "runtime/javaCalls.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/osThread.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/timer.hpp" -#include "utilities/events.hpp" -#include "utilities/vmError.hpp" - -# include // needed first to avoid name collision for "std" with SC 5.0 - -// put OS-includes here -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# define _STRUCTURED_PROC 1 // this gets us the new structured proc interfaces of 5.6 & later -# include // see comment in - -#define MAX_PATH (2 * K) - -// Minimum usable stack sizes required to get to user code. Space for -// HotSpot guard pages is added later. -size_t os::Posix::_compiler_thread_min_stack_allowed = 104 * K; -size_t os::Posix::_java_thread_min_stack_allowed = 86 * K; -size_t os::Posix::_vm_internal_thread_min_stack_allowed = 128 * K; - -static void handle_unflushed_register_windows(gwindows_t *win) { - int restore_count = win->wbcnt; - int i; - - for(i=0; ispbuf[i]) + STACK_BIAS; - address reg_win = (address)&win->wbuf[i]; - memcpy(sp,reg_win,sizeof(struct rwindow)); - } -} - -char* os::non_memory_address_word() { - // Must never look like an address returned by reserve_memory, - // even in its subfields (as defined by the CPU immediate fields, - // if the CPU splits constants across multiple instructions). - // On SPARC, 0 != %hi(any real address), because there is no - // allocation in the first 1Kb of the virtual address space. - return (char*) 0; -} - -// Validate a ucontext retrieved from walking a uc_link of a ucontext. -// There are issues with libthread giving out uc_links for different threads -// on the same uc_link chain and bad or circular links. -// -bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) { - if (valid >= suspect || - valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags || - valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp || - valid->uc_stack.ss_size != suspect->uc_stack.ss_size) { - DEBUG_ONLY(tty->print_cr("valid_ucontext: failed test 1");) - return false; - } - - if (thread->is_Java_thread()) { - if (!thread->is_in_full_stack_checked((address)suspect)) { - DEBUG_ONLY(tty->print_cr("valid_ucontext: uc_link not in thread stack");) - return false; - } - address _sp = (address)((intptr_t)suspect->uc_mcontext.gregs[REG_SP] + STACK_BIAS); - if (!thread->is_in_full_stack_checked(_sp) || - !frame::is_valid_stack_pointer(((JavaThread*)thread)->base_of_stack_pointer(), (intptr_t*)_sp)) { - DEBUG_ONLY(tty->print_cr("valid_ucontext: stackpointer not in thread stack");) - return false; - } - } - return true; -} - -// We will only follow one level of uc_link since there are libthread -// issues with ucontext linking and it is better to be safe and just -// let caller retry later. -const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, - const ucontext_t *uc) { - - const ucontext_t *retuc = NULL; - - // Sometimes the topmost register windows are not properly flushed. - // i.e., if the kernel would have needed to take a page fault - if (uc != NULL && uc->uc_mcontext.gwins != NULL) { - ::handle_unflushed_register_windows(uc->uc_mcontext.gwins); - } - - if (uc != NULL) { - if (uc->uc_link == NULL) { - // cannot validate without uc_link so accept current ucontext - retuc = uc; - } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { - // first ucontext is valid so try the next one - uc = uc->uc_link; - if (uc->uc_link == NULL) { - // cannot validate without uc_link so accept current ucontext - retuc = uc; - } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { - // the ucontext one level down is also valid so return it - retuc = uc; - } - } - } - return retuc; -} - -// Assumes ucontext is valid -ExtendedPC os::Solaris::ucontext_get_ExtendedPC(const ucontext_t *uc) { - address pc = (address)uc->uc_mcontext.gregs[REG_PC]; - // set npc to zero to avoid using it for safepoint, good for profiling only - return ExtendedPC(pc); -} - -void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) { - uc->uc_mcontext.gregs [REG_PC] = (greg_t) pc; - uc->uc_mcontext.gregs [REG_nPC] = (greg_t) (pc + 4); -} - -// Assumes ucontext is valid -intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) { - return (intptr_t*)((intptr_t)uc->uc_mcontext.gregs[REG_SP] + STACK_BIAS); -} - -// Solaris X86 only -intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) { - ShouldNotReachHere(); - return NULL; -} - -address os::Solaris::ucontext_get_pc(const ucontext_t *uc) { - return (address) uc->uc_mcontext.gregs[REG_PC]; -} - - -// For Forte Analyzer AsyncGetCallTrace profiling support - thread -// is currently interrupted by SIGPROF. -// -// ret_fp parameter is only used by Solaris X86. -// -// The difference between this and os::fetch_frame_from_context() is that -// here we try to skip nested signal frames. -// This method is also used for stack overflow signal handling. -ExtendedPC os::Solaris::fetch_frame_from_ucontext(Thread* thread, - const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { - - assert(thread != NULL, "just checking"); - assert(ret_sp != NULL, "just checking"); - assert(ret_fp == NULL, "just checking"); - - const ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc); - - return os::fetch_frame_from_context(luc, ret_sp, ret_fp); -} - - -// ret_fp parameter is only used by Solaris X86. -ExtendedPC os::fetch_frame_from_context(const void* ucVoid, - intptr_t** ret_sp, intptr_t** ret_fp) { - - ExtendedPC epc; - const ucontext_t *uc = (const ucontext_t*)ucVoid; - - if (uc != NULL) { - epc = os::Solaris::ucontext_get_ExtendedPC(uc); - if (ret_sp) *ret_sp = os::Solaris::ucontext_get_sp(uc); - } else { - // construct empty ExtendedPC for return value checking - epc = ExtendedPC(NULL); - if (ret_sp) *ret_sp = (intptr_t *)NULL; - } - - return epc; -} - -frame os::fetch_frame_from_context(const void* ucVoid) { - intptr_t* sp; - intptr_t* fp; - ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); - return frame(sp, frame::unpatchable, epc.pc()); -} - -frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { - intptr_t* sp; - ExtendedPC epc = os::Solaris::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, NULL); - return frame(sp, frame::unpatchable, epc.pc()); -} - -bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { - address pc = (address) os::Solaris::ucontext_get_pc(uc); - if (Interpreter::contains(pc)) { - *fr = os::fetch_frame_from_ucontext(thread, uc); - if (!fr->is_first_java_frame()) { - assert(fr->safe_for_sender(thread), "Safety check"); - *fr = fr->java_sender(); - } - } else { - // more complex code with compiled code - assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); - CodeBlob* cb = CodeCache::find_blob(pc); - if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { - // Not sure where the pc points to, fallback to default - // stack overflow handling - return false; - } else { - // Returned frame will be the caller of the method that faults on the stack bang. - // Register window not yet rotated (happens at SAVE after stack bang), so there is no new - // frame to go with the faulting PC. Using caller SP that is still in SP, and caller PC - // that was written to O7 at call. - intptr_t* sp = os::Solaris::ucontext_get_sp(uc); - address pc = (address)uc->uc_mcontext.gregs[REG_O7]; - *fr = frame(sp, frame::unpatchable, pc); - - if (!fr->is_java_frame()) { - assert(fr->safe_for_sender(thread), "Safety check"); - *fr = fr->java_sender(); - } - } - } - assert(fr->is_java_frame(), "Safety check"); - return true; -} - -frame os::get_sender_for_C_frame(frame* fr) { - return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc()); -} - -// Returns an estimate of the current stack pointer. Result must be guaranteed to -// point into the calling threads stack, and be no lower than the current stack -// pointer. -address os::current_stack_pointer() { - volatile int dummy; - address sp = (address)&dummy + 8; // %%%% need to confirm if this is right - return sp; -} - -frame os::current_frame() { - intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()(); - frame myframe(sp, frame::unpatchable, - CAST_FROM_FN_PTR(address, os::current_frame)); - if (os::is_first_C_frame(&myframe)) { - // stack is not walkable - return frame(NULL, NULL, false); - } else { - return os::get_sender_for_C_frame(&myframe); - } -} - -bool os::is_allocatable(size_t bytes) { - return true; -} - -extern "C" JNIEXPORT int -JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away - // (no destructors can be run) - os::ThreadCrashProtection::check_crash_protection(sig, t); - - SignalHandlerMark shm(t); - - if(sig == SIGPIPE || sig == SIGXFSZ) { - if (os::Solaris::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (os::Solaris::signal_handlers_are_installed) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = (JavaThread*)t; - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } - - if (sig == ASYNC_SIGNAL) { - if (thread || vmthread) { - OSThread::SR_handler(t, uc); - return true; - } else if (os::Solaris::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // If ASYNC_SIGNAL not chained, and this is a non-vm and - // non-java thread - return true; - } - } - - if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { - // can't decode this kind of signal - info = NULL; - } else { - assert(sig == info->si_signo, "bad siginfo"); - } - - // decide if this trap can be handled by a stub - address stub = NULL; - - address pc = NULL; - address npc = NULL; - - //%note os_trap_1 - if (info != NULL && uc != NULL && thread != NULL) { - // factor me: getPCfromContext - pc = (address) uc->uc_mcontext.gregs[REG_PC]; - npc = (address) uc->uc_mcontext.gregs[REG_nPC]; - - // SafeFetch() support - if (StubRoutines::is_safefetch_fault(pc)) { - os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return 1; - } - - // Handle ALL stack overflow variations here - if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { - address addr = (address) info->si_addr; - if (thread->in_stack_yellow_reserved_zone(addr)) { - // Sometimes the register windows are not properly flushed. - if(uc->uc_mcontext.gwins != NULL) { - ::handle_unflushed_register_windows(uc->uc_mcontext.gwins); - } - if (thread->thread_state() == _thread_in_Java) { - if (thread->in_stack_reserved_zone(addr)) { - frame fr; - if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) { - assert(fr.is_java_frame(), "Must be a Java frame"); - frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); - if (activation.sp() != NULL) { - thread->disable_stack_reserved_zone(); - RegisterMap map(thread); - int frame_size = activation.frame_size(&map); - thread->set_reserved_stack_activation((address)(((address)activation.sp()) - STACK_BIAS)); - return true; - } - } - } - // Throw a stack overflow exception. Guard pages will be reenabled - // while unwinding the stack. - thread->disable_stack_yellow_reserved_zone(); - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); - } else { - // Thread was in the vm or native code. Return and try to finish. - thread->disable_stack_yellow_reserved_zone(); - return true; - } - } else if (thread->in_stack_red_zone(addr)) { - // Fatal red zone violation. Disable the guard pages and fall through - // to handle_unexpected_exception way down below. - thread->disable_stack_red_zone(); - tty->print_raw_cr("An irrecoverable stack overflow has occurred."); - // Sometimes the register windows are not properly flushed. - if(uc->uc_mcontext.gwins != NULL) { - ::handle_unflushed_register_windows(uc->uc_mcontext.gwins); - } - } - } - - - if (thread->thread_state() == _thread_in_vm || - thread->thread_state() == _thread_in_native) { - if (sig == SIGBUS && thread->doing_unsafe_access()) { - if (UnsafeCopyMemory::contains_pc(pc)) { - npc = UnsafeCopyMemory::page_error_continue_pc(pc); - } - stub = SharedRuntime::handle_unsafe_access(thread, npc); - } - } - - else if (thread->thread_state() == _thread_in_Java) { - // Java thread running in Java code => find exception handler if any - // a fault inside compiled code, the interpreter, or a stub - - // Support Safepoint Polling - if (sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) { - stub = SharedRuntime::get_poll_stub(pc); - } - - // Not needed on x86 solaris because verify_oops doesn't generate - // SEGV/BUS like sparc does. - if ( (sig == SIGSEGV || sig == SIGBUS) - && pc >= MacroAssembler::_verify_oop_implicit_branch[0] - && pc < MacroAssembler::_verify_oop_implicit_branch[1] ) { - stub = MacroAssembler::_verify_oop_implicit_branch[2]; - warning("fixed up memory fault in +VerifyOops at address " INTPTR_FORMAT, info->si_addr); - } - - // This is not factored because on x86 solaris the patching for - // zombies does not generate a SEGV. - else if (sig == SIGSEGV && nativeInstruction_at(pc)->is_zombie()) { - // zombie method (ld [%g0],%o7 instruction) - stub = SharedRuntime::get_handle_wrong_method_stub(); - - // At the stub it needs to look like a call from the caller of this - // method (not a call from the segv site). - pc = (address)uc->uc_mcontext.gregs[REG_O7]; - } - else if (sig == SIGBUS && info->si_code == BUS_OBJERR) { - // BugId 4454115: A read from a MappedByteBuffer can fault - // here if the underlying file has been truncated. - // Do not crash the VM in such a case. - CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - CompiledMethod* nm = cb->as_compiled_method_or_null(); - bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); - if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) { - if (is_unsafe_arraycopy) { - npc = UnsafeCopyMemory::page_error_continue_pc(pc); - } - stub = SharedRuntime::handle_unsafe_access(thread, npc); - } - } - - else if (sig == SIGFPE && info->si_code == FPE_INTDIV) { - // integer divide by zero - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - } - else if (sig == SIGFPE && info->si_code == FPE_FLTDIV) { - // floating-point divide by zero - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - } -#ifdef COMPILER2 - else if (sig == SIGILL && nativeInstruction_at(pc)->is_ic_miss_trap()) { -#ifdef ASSERT - #ifdef TIERED - CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - assert(cb->is_compiled_by_c2(), "Wrong compiler"); - #endif // TIERED -#endif // ASSERT - // Inline cache missed and user trap "Tne G0+ST_RESERVED_FOR_USER_0+2" taken. - stub = SharedRuntime::get_ic_miss_stub(); - // At the stub it needs to look like a call from the caller of this - // method (not a call from the segv site). - pc = (address)uc->uc_mcontext.gregs[REG_O7]; - } -#endif // COMPILER2 - - else if (sig == SIGSEGV && info->si_code > 0 && MacroAssembler::uses_implicit_null_check(info->si_addr)) { - // Determination of interpreter/vtable stub/compiled code null exception - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); - } - } - - // jni_fast_GetField can trap at certain pc's if a GC kicks in - // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { - address addr = JNI_FastGetField::find_slowcase_pc(pc); - if (addr != (address)-1) { - stub = addr; - } - } - } - - if (stub != NULL) { - // save all thread context in case we need to restore it - - thread->set_saved_exception_pc(pc); - thread->set_saved_exception_npc(npc); - - // simulate a branch to the stub (a "call" in the safepoint stub case) - // factor me: setPC - os::Solaris::ucontext_set_pc(uc, stub); - - return true; - } - - // signal-chaining - if (os::Solaris::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (!os::Solaris::libjsig_is_loaded) { - struct sigaction oldAct; - sigaction(sig, (struct sigaction *)0, &oldAct); - if (oldAct.sa_sigaction != signalHandler) { - void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) - : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - warning("Unexpected Signal %d occurred under user-defined signal handler " INTPTR_FORMAT, sig, (intptr_t)sighand); - } - } - - if (pc == NULL && uc != NULL) { - pc = (address) uc->uc_mcontext.gregs[REG_PC]; - } - - // Sometimes the register windows are not properly flushed. - if(uc->uc_mcontext.gwins != NULL) { - ::handle_unflushed_register_windows(uc->uc_mcontext.gwins); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - // Determine which sort of error to throw. Out of swap may signal - // on the thread stack, which could get a mapping error when touched. - address addr = (address) info->si_addr; - if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) { - vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack."); - } - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); - return false; -} - -void os::print_context(outputStream *st, const void *context) { - if (context == NULL) return; - - const ucontext_t *uc = (const ucontext_t*)context; - st->print_cr("Registers:"); - - st->print_cr(" G1=" INTPTR_FORMAT " G2=" INTPTR_FORMAT - " G3=" INTPTR_FORMAT " G4=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_G1], - uc->uc_mcontext.gregs[REG_G2], - uc->uc_mcontext.gregs[REG_G3], - uc->uc_mcontext.gregs[REG_G4]); - st->print_cr(" G5=" INTPTR_FORMAT " G6=" INTPTR_FORMAT - " G7=" INTPTR_FORMAT " Y=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_G5], - uc->uc_mcontext.gregs[REG_G6], - uc->uc_mcontext.gregs[REG_G7], - uc->uc_mcontext.gregs[REG_Y]); - st->print_cr(" O0=" INTPTR_FORMAT " O1=" INTPTR_FORMAT - " O2=" INTPTR_FORMAT " O3=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_O0], - uc->uc_mcontext.gregs[REG_O1], - uc->uc_mcontext.gregs[REG_O2], - uc->uc_mcontext.gregs[REG_O3]); - st->print_cr(" O4=" INTPTR_FORMAT " O5=" INTPTR_FORMAT - " O6=" INTPTR_FORMAT " O7=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_O4], - uc->uc_mcontext.gregs[REG_O5], - uc->uc_mcontext.gregs[REG_O6], - uc->uc_mcontext.gregs[REG_O7]); - - - intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); - st->print_cr(" L0=" INTPTR_FORMAT " L1=" INTPTR_FORMAT - " L2=" INTPTR_FORMAT " L3=" INTPTR_FORMAT, - sp[L0->sp_offset_in_saved_window()], - sp[L1->sp_offset_in_saved_window()], - sp[L2->sp_offset_in_saved_window()], - sp[L3->sp_offset_in_saved_window()]); - st->print_cr(" L4=" INTPTR_FORMAT " L5=" INTPTR_FORMAT - " L6=" INTPTR_FORMAT " L7=" INTPTR_FORMAT, - sp[L4->sp_offset_in_saved_window()], - sp[L5->sp_offset_in_saved_window()], - sp[L6->sp_offset_in_saved_window()], - sp[L7->sp_offset_in_saved_window()]); - st->print_cr(" I0=" INTPTR_FORMAT " I1=" INTPTR_FORMAT - " I2=" INTPTR_FORMAT " I3=" INTPTR_FORMAT, - sp[I0->sp_offset_in_saved_window()], - sp[I1->sp_offset_in_saved_window()], - sp[I2->sp_offset_in_saved_window()], - sp[I3->sp_offset_in_saved_window()]); - st->print_cr(" I4=" INTPTR_FORMAT " I5=" INTPTR_FORMAT - " I6=" INTPTR_FORMAT " I7=" INTPTR_FORMAT, - sp[I4->sp_offset_in_saved_window()], - sp[I5->sp_offset_in_saved_window()], - sp[I6->sp_offset_in_saved_window()], - sp[I7->sp_offset_in_saved_window()]); - - st->print_cr(" PC=" INTPTR_FORMAT " nPC=" INTPTR_FORMAT, - uc->uc_mcontext.gregs[REG_PC], - uc->uc_mcontext.gregs[REG_nPC]); - st->cr(); - st->cr(); - - st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); - print_hex_dump(st, (address)sp, (address)(sp + 32), sizeof(intptr_t)); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc); - address pc = epc.pc(); - print_instructions(st, pc, sizeof(char)); - st->cr(); -} - -void os::print_register_info(outputStream *st, const void *context) { - if (context == NULL) return; - - const ucontext_t *uc = (const ucontext_t*)context; - intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is only for the "general purpose" registers - st->print("G1="); print_location(st, uc->uc_mcontext.gregs[REG_G1]); - st->print("G2="); print_location(st, uc->uc_mcontext.gregs[REG_G2]); - st->print("G3="); print_location(st, uc->uc_mcontext.gregs[REG_G3]); - st->print("G4="); print_location(st, uc->uc_mcontext.gregs[REG_G4]); - st->print("G5="); print_location(st, uc->uc_mcontext.gregs[REG_G5]); - st->print("G6="); print_location(st, uc->uc_mcontext.gregs[REG_G6]); - st->print("G7="); print_location(st, uc->uc_mcontext.gregs[REG_G7]); - st->cr(); - - st->print("O0="); print_location(st, uc->uc_mcontext.gregs[REG_O0]); - st->print("O1="); print_location(st, uc->uc_mcontext.gregs[REG_O1]); - st->print("O2="); print_location(st, uc->uc_mcontext.gregs[REG_O2]); - st->print("O3="); print_location(st, uc->uc_mcontext.gregs[REG_O3]); - st->print("O4="); print_location(st, uc->uc_mcontext.gregs[REG_O4]); - st->print("O5="); print_location(st, uc->uc_mcontext.gregs[REG_O5]); - st->print("O6="); print_location(st, uc->uc_mcontext.gregs[REG_O6]); - st->print("O7="); print_location(st, uc->uc_mcontext.gregs[REG_O7]); - st->cr(); - - st->print("L0="); print_location(st, sp[L0->sp_offset_in_saved_window()]); - st->print("L1="); print_location(st, sp[L1->sp_offset_in_saved_window()]); - st->print("L2="); print_location(st, sp[L2->sp_offset_in_saved_window()]); - st->print("L3="); print_location(st, sp[L3->sp_offset_in_saved_window()]); - st->print("L4="); print_location(st, sp[L4->sp_offset_in_saved_window()]); - st->print("L5="); print_location(st, sp[L5->sp_offset_in_saved_window()]); - st->print("L6="); print_location(st, sp[L6->sp_offset_in_saved_window()]); - st->print("L7="); print_location(st, sp[L7->sp_offset_in_saved_window()]); - st->cr(); - - st->print("I0="); print_location(st, sp[I0->sp_offset_in_saved_window()]); - st->print("I1="); print_location(st, sp[I1->sp_offset_in_saved_window()]); - st->print("I2="); print_location(st, sp[I2->sp_offset_in_saved_window()]); - st->print("I3="); print_location(st, sp[I3->sp_offset_in_saved_window()]); - st->print("I4="); print_location(st, sp[I4->sp_offset_in_saved_window()]); - st->print("I5="); print_location(st, sp[I5->sp_offset_in_saved_window()]); - st->print("I6="); print_location(st, sp[I6->sp_offset_in_saved_window()]); - st->print("I7="); print_location(st, sp[I7->sp_offset_in_saved_window()]); - st->cr(); -} - -void os::Solaris::init_thread_fpu_state(void) { - // Nothing needed on Sparc. -} - -#ifndef PRODUCT -void os::verify_stack_alignment() { -} -#endif - -int os::extra_bang_size_in_bytes() { - // SPARC does not require an additional stack bang. - return 0; -} diff --git a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_OS_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_OS_SOLARIS_SPARC_HPP - - // - // NOTE: we are back in class os here, not Solaris - // - static int32_t (*atomic_xchg_func) (int32_t, volatile int32_t*); - static int32_t (*atomic_cmpxchg_func) (int32_t, volatile int32_t*, int32_t); - static int64_t (*atomic_cmpxchg_long_func)(int64_t, volatile int64_t*, int64_t); - static int32_t (*atomic_add_func) (int32_t, volatile int32_t*); - - static int32_t atomic_xchg_bootstrap (int32_t, volatile int32_t*); - static int32_t atomic_cmpxchg_bootstrap (int32_t, volatile int32_t*, int32_t); - static int64_t atomic_cmpxchg_long_bootstrap(int64_t, volatile int64_t*, int64_t); - static int32_t atomic_add_bootstrap (int32_t, volatile int32_t*); - - static void setup_fpu() {} - - static bool is_allocatable(size_t bytes); - - // Used to register dynamic code cache area with the OS - // Note: Currently only used in 64 bit Windows implementations - static bool register_code_area(char *low, char *high) { return true; } - -#endif // OS_CPU_SOLARIS_SPARC_OS_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp b/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/prefetch_solaris_sparc.inline.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_PREFETCH_SOLARIS_SPARC_INLINE_HPP -#define OS_CPU_SOLARIS_SPARC_PREFETCH_SOLARIS_SPARC_INLINE_HPP - -#include "runtime/prefetch.hpp" - -// For Sun Studio inplementation is in solaris_sparc.il -// For gcc inplementation is just below -extern "C" void _Prefetch_read (void *loc, intx interval); -extern "C" void _Prefetch_write(void *loc, intx interval); - -inline void Prefetch::read(void *loc, intx interval) { - _Prefetch_read(loc, interval); -} - -inline void Prefetch::write(void *loc, intx interval) { - _Prefetch_write(loc, interval); -} - -#endif // OS_CPU_SOLARIS_SPARC_PREFETCH_SOLARIS_SPARC_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il +++ /dev/null @@ -1,120 +0,0 @@ -// -// Copyright (c) 2002, 2017, 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. -// -// - - // Get the raw thread ID from %g7 - - .inline _raw_thread_id, 0 - .register %g7,#scratch - .volatile - mov %g7, %o0 - .nonvolatile - .end - - - // Support for jlong Atomic::load and Atomic::store on v9. - // - // void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst) - // - // Arguments: - // src: O0 - // dest: O1 - // - // Overwrites O2 - - .inline _Atomic_move_long_v9,2 - .volatile - ldx [%o0], %o2 - stx %o2, [%o1] - .nonvolatile - .end - - // Support for void Prefetch::read(void *loc, intx interval) - // - // Prefetch for several reads. - - .inline _Prefetch_read, 2 - .volatile - prefetch [%o0+%o1], 0 - .nonvolatile - .end - - - // Support for void Prefetch::write(void *loc, intx interval) - // - // Prefetch for several writes. - - .inline _Prefetch_write, 2 - .volatile - prefetch [%o0+%o1], 2 - .nonvolatile - .end - - - // Support for void Copy::conjoint_jlongs_atomic(jlong* from, jlong* to, size_t count) - // - // 32-bit - // - // Arguments: - // from: O0 - // to: O1 - // count: O2 treated as signed - // - // Clobbers: - // long_value: O2, O3 - // count: O4 - // - // if (from > to) { - // while (--count >= 0) { - // *to++ = *from++; - // } - // } else { - // while (--count >= 0) { - // to[count] = from[count]; - // } - // } - .inline _Copy_conjoint_jlongs_atomic, 3 - .volatile - cmp %o0, %o1 - bleu 4f - sll %o2, 3, %o4 - ba 2f - 1: - subcc %o4, 8, %o4 - std %o2, [%o1] - add %o0, 8, %o0 - add %o1, 8, %o1 - 2: - bge,a 1b - ldd [%o0], %o2 - ba 5f - nop - 3: - std %o2, [%o1+%o4] - 4: - subcc %o4, 8, %o4 - bge,a 3b - ldd [%o0+%o4], %o2 - 5: - .nonvolatile - .end diff --git a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.s b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.s deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.s +++ /dev/null @@ -1,82 +0,0 @@ -!! -!! Copyright (c) 2005, 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. -!! - - !! Possibilities: - !! -- membar - !! -- CAS (SP + BIAS, G0, G0) - !! -- wr %g0, %asi - - .global SpinPause - .align 32 -SpinPause: - retl - mov %g0, %o0 - - - - .globl _Copy_conjoint_jlongs_atomic - .align 32 - .global _Copy_conjoint_jlongs_atomic - _Copy_conjoint_jlongs_atomic: - cmp %o0, %o1 - bleu 4f - sll %o2, 3, %o4 - ba 2f - 1: - subcc %o4, 8, %o4 - std %o2, [%o1] - add %o0, 8, %o0 - add %o1, 8, %o1 - 2: - bge,a 1b - ldd [%o0], %o2 - ba 5f - nop - 3: - std %o2, [%o1+%o4] - 4: - subcc %o4, 8, %o4 - bge,a 3b - ldd [%o0+%o4], %o2 - 5: - retl - nop - - - - .globl _raw_thread_id - .align 32 - _raw_thread_id: - .register %g7, #scratch - retl - mov %g7, %o0 - - - .globl _flush_reg_windows - .align 32 - _flush_reg_windows: - ta 0x03 - retl - mov %fp, %o0 - - diff --git a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2003, 2018, 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. - * - */ - -#include "precompiled.hpp" -#include "memory/metaspaceShared.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/thread.inline.hpp" - -frame JavaThread::pd_last_frame() { - assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); - assert(_anchor.walkable(), "thread has not dumped its register windows yet"); - - assert(_anchor.last_Java_pc() != NULL, "Ack no pc!"); - return frame(last_Java_sp(), frame::unpatchable, _anchor.last_Java_pc()); -} - -// For Forte Analyzer AsyncGetCallTrace profiling support - thread is -// currently interrupted by SIGPROF -// -// NOTE: On Solaris, register windows are flushed in the signal handler -// except for possibly the top frame. -// -bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, - void* ucontext, bool isInJava) { - - assert(Thread::current() == this, "caller must be current thread"); - return pd_get_top_frame(fr_addr, ucontext, isInJava, true); -} - -bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { - // get ucontext somehow - return pd_get_top_frame(fr_addr, ucontext, isInJava, false); -} - -bool JavaThread::pd_get_top_frame(frame* fr_addr, - void* ucontext, bool isInJava, bool makeWalkable) { - assert(this->is_Java_thread(), "must be JavaThread"); - - JavaThread* jt = (JavaThread *)this; - - if (!isInJava && makeWalkable) { - // make_walkable flushes register windows and grabs last_Java_pc - // which can not be done if the ucontext sp matches last_Java_sp - // stack walking utilities assume last_Java_pc set if marked flushed - jt->frame_anchor()->make_walkable(jt); - } - - // If we have a walkable last_Java_frame, then we should use it - // even if isInJava == true. It should be more reliable than - // ucontext info. - if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { - *fr_addr = jt->pd_last_frame(); - return true; - } - - ucontext_t* uc = (ucontext_t*) ucontext; - - // At this point, we don't have a walkable last_Java_frame, so - // we try to glean some information out of the ucontext. - intptr_t* ret_sp; - ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, - &ret_sp, NULL /* ret_fp only used on Solaris X86 */); - if (addr.pc() == NULL || ret_sp == NULL) { - // ucontext wasn't useful - return false; - } - - if (MetaspaceShared::is_in_trampoline_frame(addr.pc())) { - // In the middle of a trampoline call. Bail out for safety. - // This happens rarely so shouldn't affect profiling. - return false; - } - - frame ret_frame(ret_sp, frame::unpatchable, addr.pc()); - - // we were running Java code when SIGPROF came in - if (isInJava) { - - - // If the frame we got is safe then it is most certainly valid - if (ret_frame.safe_for_sender(jt)) { - *fr_addr = ret_frame; - return true; - } - - // If it isn't safe then we can try several things to try and get - // a good starting point. - // - // On sparc the frames are almost certainly walkable in the sense - // of sp/fp linkages. However because of recycling of windows if - // a piece of code does multiple save's where the initial save creates - // a real frame with a return pc and the succeeding save's are used to - // simply get free registers and have no real pc then the pc linkage on these - // "inner" temporary frames will be bogus. - // Since there is in general only a nesting level like - // this one deep in general we'll try and unwind such an "inner" frame - // here ourselves and see if it makes sense - - frame unwind_frame(ret_frame.fp(), frame::unpatchable, addr.pc()); - - if (unwind_frame.safe_for_sender(jt)) { - *fr_addr = unwind_frame; - return true; - } - - // Well that didn't work. Most likely we're toast on this tick - // The previous code would try this. I think it is dubious in light - // of changes to safe_for_sender and the unwind trick above but - // if it gets us a safe frame who wants to argue. - - // If we have a last_Java_sp, then the SIGPROF signal caught us - // right when we were transitioning from _thread_in_Java to a new - // JavaThreadState. We use last_Java_sp instead of the sp from - // the ucontext since it should be more reliable. - - if (jt->has_last_Java_frame()) { - ret_sp = jt->last_Java_sp(); - frame ret_frame2(ret_sp, frame::unpatchable, addr.pc()); - if (ret_frame2.safe_for_sender(jt)) { - *fr_addr = ret_frame2; - return true; - } - } - - // This is the best we can do. We will only be able to decode the top frame - - *fr_addr = ret_frame; - return true; - } - - // At this point, we know we weren't running Java code. We might - // have a last_Java_sp, but we don't have a walkable frame. - // However, we might still be able to construct something useful - // if the thread was running native code. - if (jt->has_last_Java_frame()) { - assert(!jt->frame_anchor()->walkable(), "case covered above"); - - frame ret_frame(jt->last_Java_sp(), frame::unpatchable, addr.pc()); - *fr_addr = ret_frame; - return true; - } - - // nothing else to try but what we found initially - - *fr_addr = ret_frame; - return true; -} - -void JavaThread::cache_global_variables() { } - diff --git a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/thread_solaris_sparc.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_THREAD_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_THREAD_SOLARIS_SPARC_HPP -private: - - void pd_initialize() { - _anchor.clear(); - _base_of_stack_pointer = NULL; - } - - frame pd_last_frame(); - - // Sometimes the trap handler needs to record both PC and NPC. - // This is a SPARC-specific companion to Thread::set_saved_exception_pc. - address _saved_exception_npc; - - // In polling_page_safepoint_handler_blob(s) we have to tail call other - // blobs without blowing any registers. A tail call requires some - // register to jump with and we can't blow any registers, so it must - // be restored in the delay slot. 'restore' cannot be used as it - // will chop the heads off of 64-bit %o registers in the 32-bit - // build. Instead we reload the registers using G2_thread and this - // location. Must be 64bits in the 32-bit LION build. - jdouble _o_reg_temps[6]; - - // a stack pointer older than any java frame stack pointer. It is - // used to validate stack pointers in frame::next_younger_sp (it - // provides the upper bound in the range check). This is necessary - // on Solaris/SPARC since the ucontext passed to a signal handler is - // sometimes corrupt and we need a way to check the extracted sp. - intptr_t* _base_of_stack_pointer; - -public: - - static int o_reg_temps_offset_in_bytes() { return offset_of(JavaThread, _o_reg_temps); } - - static ByteSize saved_exception_npc_offset() { return byte_offset_of(JavaThread,_saved_exception_npc); } - - address saved_exception_npc() { return _saved_exception_npc; } - void set_saved_exception_npc(address a) { _saved_exception_npc = a; } - - -public: - - intptr_t* base_of_stack_pointer() { return _base_of_stack_pointer; } - - void set_base_of_stack_pointer(intptr_t* base_sp) { - _base_of_stack_pointer = base_sp; - } - - void record_base_of_stack_pointer() { - intptr_t *sp = (intptr_t *)(((intptr_t)StubRoutines::Sparc::flush_callers_register_windows_func()())); - intptr_t *ysp; - while((ysp = (intptr_t*)sp[FP->sp_offset_in_saved_window()]) != NULL) { - sp = (intptr_t *)((intptr_t)ysp + STACK_BIAS); - } - _base_of_stack_pointer = sp; - } - - bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, - bool isInJava); - - bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava); -private: - bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava, bool makeWalkable); -public: - - // These routines are only used on cpu architectures that - // have separate register stacks (Itanium). - static bool register_stack_overflow() { return false; } - static void enable_register_stack_guard() {} - static void disable_register_stack_guard() {} - -#endif // OS_CPU_SOLARIS_SPARC_THREAD_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/vmStructs_solaris_sparc.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_SPARC_VMSTRUCTS_SOLARIS_SPARC_HPP -#define OS_CPU_SOLARIS_SPARC_VMSTRUCTS_SOLARIS_SPARC_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_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) \ - nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) - -#define VM_TYPES_OS_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_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ - declare_constant(JavaFrameAnchor::flushed) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#endif // OS_CPU_SOLARIS_SPARC_VMSTRUCTS_SOLARIS_SPARC_HPP diff --git a/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp b/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_sparc/vm_version_solaris_sparc.cpp +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (c) 2006, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "logging/log.hpp" -#include "memory/allocation.hpp" -#include "memory/allocation.inline.hpp" -#include "runtime/os.hpp" -#include "runtime/vm_version.hpp" - -#include -#include -#include -#include -#include - -extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result); - -// Functions from the library we need (signatures should match those in picl.h) -extern "C" { - typedef int (*picl_initialize_func_t)(void); - typedef int (*picl_shutdown_func_t)(void); - typedef int (*picl_get_root_func_t)(picl_nodehdl_t *nodehandle); - typedef int (*picl_walk_tree_by_class_func_t)(picl_nodehdl_t rooth, - const char *classname, void *c_args, - int (*callback_fn)(picl_nodehdl_t hdl, void *args)); - typedef int (*picl_get_prop_by_name_func_t)(picl_nodehdl_t nodeh, const char *nm, - picl_prophdl_t *ph); - typedef int (*picl_get_propval_func_t)(picl_prophdl_t proph, void *valbuf, size_t sz); - typedef int (*picl_get_propinfo_func_t)(picl_prophdl_t proph, picl_propinfo_t *pi); -} - -class PICL { - // Pointers to functions in the library - picl_initialize_func_t _picl_initialize; - picl_shutdown_func_t _picl_shutdown; - picl_get_root_func_t _picl_get_root; - picl_walk_tree_by_class_func_t _picl_walk_tree_by_class; - picl_get_prop_by_name_func_t _picl_get_prop_by_name; - picl_get_propval_func_t _picl_get_propval; - picl_get_propinfo_func_t _picl_get_propinfo; - // Handle to the library that is returned by dlopen - void *_dl_handle; - - bool open_library(); - void close_library(); - - template bool bind(FuncType& func, const char* name); - bool bind_library_functions(); - - // Get a value of the integer property. The value in the tree can be either 32 or 64 bit - // depending on the platform. The result is converted to int. - int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { - picl_propinfo_t pinfo; - picl_prophdl_t proph; - if (_picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || - _picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { - return PICL_FAILURE; - } - - if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) { - assert(false, "Invalid property type"); - return PICL_FAILURE; - } - if (pinfo.size == sizeof(int64_t)) { - int64_t val; - if (_picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { - return PICL_FAILURE; - } - *result = static_cast(val); - } else if (pinfo.size == sizeof(int32_t)) { - int32_t val; - if (_picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { - return PICL_FAILURE; - } - *result = static_cast(val); - } else { - assert(false, "Unexpected integer property size"); - return PICL_FAILURE; - } - return PICL_SUCCESS; - } - - // Visitor and a state machine that visits integer properties and verifies that the - // values are the same. Stores the unique value observed. - class UniqueValueVisitor { - PICL *_picl; - enum { - INITIAL, // Start state, no assignments happened - ASSIGNED, // Assigned a value - INCONSISTENT // Inconsistent value seen - } _state; - int _value; - public: - UniqueValueVisitor(PICL* picl) : _picl(picl), _state(INITIAL) { } - int value() { - assert(_state == ASSIGNED, "Precondition"); - return _value; - } - void set_value(int value) { - assert(_state == INITIAL, "Precondition"); - _value = value; - _state = ASSIGNED; - } - bool is_initial() { return _state == INITIAL; } - bool is_assigned() { return _state == ASSIGNED; } - bool is_inconsistent() { return _state == INCONSISTENT; } - void set_inconsistent() { _state = INCONSISTENT; } - - bool visit(picl_nodehdl_t nodeh, const char* name) { - assert(!is_inconsistent(), "Precondition"); - int curr; - if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { - if (!is_assigned()) { // first iteration - set_value(curr); - } else if (curr != value()) { // following iterations - set_inconsistent(); - } - return true; - } - return false; - } - }; - - class CPUVisitor { - UniqueValueVisitor _l1_visitor; - UniqueValueVisitor _l2_visitor; - int _limit; // number of times visit() can be run - public: - CPUVisitor(PICL *picl, int limit) : _l1_visitor(picl), _l2_visitor(picl), _limit(limit) {} - static int visit(picl_nodehdl_t nodeh, void *arg) { - CPUVisitor *cpu_visitor = static_cast(arg); - UniqueValueVisitor* l1_visitor = cpu_visitor->l1_visitor(); - UniqueValueVisitor* l2_visitor = cpu_visitor->l2_visitor(); - if (!l1_visitor->is_inconsistent()) { - l1_visitor->visit(nodeh, "l1-dcache-line-size"); - } - static const char* l2_data_cache_line_property_name = NULL; - // On the first visit determine the name of the l2 cache line size property and memoize it. - if (l2_data_cache_line_property_name == NULL) { - assert(!l2_visitor->is_inconsistent(), "First iteration cannot be inconsistent"); - l2_data_cache_line_property_name = "l2-cache-line-size"; - if (!l2_visitor->visit(nodeh, l2_data_cache_line_property_name)) { - l2_data_cache_line_property_name = "l2-dcache-line-size"; - l2_visitor->visit(nodeh, l2_data_cache_line_property_name); - } - } else { - if (!l2_visitor->is_inconsistent()) { - l2_visitor->visit(nodeh, l2_data_cache_line_property_name); - } - } - - if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) { - return PICL_WALK_TERMINATE; - } - cpu_visitor->_limit--; - if (cpu_visitor->_limit <= 0) { - return PICL_WALK_TERMINATE; - } - return PICL_WALK_CONTINUE; - } - UniqueValueVisitor* l1_visitor() { return &_l1_visitor; } - UniqueValueVisitor* l2_visitor() { return &_l2_visitor; } - }; - int _L1_data_cache_line_size; - int _L2_data_cache_line_size; -public: - static int visit_cpu(picl_nodehdl_t nodeh, void *state) { - return CPUVisitor::visit(nodeh, state); - } - - PICL(bool is_fujitsu, bool is_sun4v) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) { - if (!open_library()) { - return; - } - if (_picl_initialize() == PICL_SUCCESS) { - picl_nodehdl_t rooth; - if (_picl_get_root(&rooth) == PICL_SUCCESS) { - const char* cpu_class = "cpu"; - // If it's a Fujitsu machine, it's a "core" - if (is_fujitsu) { - cpu_class = "core"; - } - CPUVisitor cpu_visitor(this, (is_sun4v && !is_fujitsu) ? 1 : os::processor_count()); - _picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper); - if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value? - _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value(); - } - if (cpu_visitor.l2_visitor()->is_assigned()) { - _L2_data_cache_line_size = cpu_visitor.l2_visitor()->value(); - } - } - _picl_shutdown(); - } - close_library(); - } - - unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } - unsigned int L2_data_cache_line_size() const { return _L2_data_cache_line_size; } -}; - - -extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) { - return PICL::visit_cpu(nodeh, result); -} - -template -bool PICL::bind(FuncType& func, const char* name) { - func = reinterpret_cast(dlsym(_dl_handle, name)); - return func != NULL; -} - -bool PICL::bind_library_functions() { - assert(_dl_handle != NULL, "library should be open"); - return bind(_picl_initialize, "picl_initialize" ) && - bind(_picl_shutdown, "picl_shutdown" ) && - bind(_picl_get_root, "picl_get_root" ) && - bind(_picl_walk_tree_by_class, "picl_walk_tree_by_class") && - bind(_picl_get_prop_by_name, "picl_get_prop_by_name" ) && - bind(_picl_get_propval, "picl_get_propval" ) && - bind(_picl_get_propinfo, "picl_get_propinfo" ); -} - -bool PICL::open_library() { - _dl_handle = dlopen("libpicl.so.1", RTLD_LAZY); - if (_dl_handle == NULL) { - return false; - } - if (!bind_library_functions()) { - assert(false, "unexpected PICL API change"); - close_library(); - return false; - } - return true; -} - -void PICL::close_library() { - assert(_dl_handle != NULL, "library should be open"); - dlclose(_dl_handle); - _dl_handle = NULL; -} - -class Sysinfo { - char* _string; -public: - Sysinfo(int si) : _string(NULL) { - char tmp; - size_t bufsize = sysinfo(si, &tmp, 1); - - if (bufsize != -1) { - char* buf = (char*) os::malloc(bufsize, mtInternal); - if (buf != NULL) { - if (sysinfo(si, buf, bufsize) == bufsize) { - _string = buf; - } else { - os::free(buf); - } - } - } - } - - ~Sysinfo() { - if (_string != NULL) { - os::free(_string); - } - } - - const char* value() const { - return _string; - } - - bool valid() const { - return _string != NULL; - } - - bool match(const char* s) const { - return valid() ? strcmp(_string, s) == 0 : false; - } - - bool match_substring(const char* s) const { - return valid() ? strstr(_string, s) != NULL : false; - } -}; - -class Sysconf { - int _value; -public: - Sysconf(int sc) : _value(-1) { - _value = sysconf(sc); - } - bool valid() const { - return _value != -1; - } - int value() const { - return _value; - } -}; - - -#ifndef _SC_DCACHE_LINESZ -#define _SC_DCACHE_LINESZ 508 /* Data cache line size */ -#endif - -#ifndef _SC_L2CACHE_LINESZ -#define _SC_L2CACHE_LINESZ 527 /* Size of L2 cache line */ -#endif - -void VM_Version::platform_features() { - uint64_t features = ISA_v9_msk; // Basic SPARC-V9 required (V8 not supported). - - assert(Sysinfo(SI_ARCHITECTURE_64).match("sparcv9"), "must be"); - - // Extract valid instruction set extensions. - uint32_t avs[AV_HW2_IDX + 1]; - uint_t avn = getisax(avs, AV_HW2_IDX + 1); - assert(avn <= 2, "should return two or less av's"); - - log_info(os, cpu)("getisax(2) returned %d words:", avn); - for (int i = 0; i < avn; i++) { - log_info(os, cpu)(" word %d: " PTR32_FORMAT, i, avs[i]); - } - - uint32_t av = avs[AV_HW1_IDX]; - - // Obsolete and 32b legacy mode capabilites NOT probed here, despite being - // set by Solaris 11.4 (onward) also on V9; AV_SPARC_MUL32, AV_SPARC_DIV32 - // and AV_SPARC_FSMULD (and AV_SPARC_V8PLUS). - - if (av & AV_SPARC_POPC) features |= ISA_popc_msk; - if (av & AV_SPARC_VIS) features |= ISA_vis1_msk; - if (av & AV_SPARC_VIS2) features |= ISA_vis2_msk; - - // Hardware capability defines introduced after Solaris 11.1: - -#ifndef AV_SPARC_FMAF -#define AV_SPARC_FMAF 0x00000100 // Fused Multiply-Add -#endif - - if (av & AV_SPARC_ASI_BLK_INIT) features |= ISA_blk_init_msk; - if (av & AV_SPARC_FMAF) features |= ISA_fmaf_msk; - if (av & AV_SPARC_VIS3) features |= ISA_vis3_msk; - if (av & AV_SPARC_HPC) features |= ISA_hpc_msk; - if (av & AV_SPARC_IMA) features |= ISA_ima_msk; - if (av & AV_SPARC_AES) features |= ISA_aes_msk; - if (av & AV_SPARC_DES) features |= ISA_des_msk; - if (av & AV_SPARC_KASUMI) features |= ISA_kasumi_msk; - if (av & AV_SPARC_CAMELLIA) features |= ISA_camellia_msk; - if (av & AV_SPARC_MD5) features |= ISA_md5_msk; - if (av & AV_SPARC_SHA1) features |= ISA_sha1_msk; - if (av & AV_SPARC_SHA256) features |= ISA_sha256_msk; - if (av & AV_SPARC_SHA512) features |= ISA_sha512_msk; - if (av & AV_SPARC_MPMUL) features |= ISA_mpmul_msk; - if (av & AV_SPARC_MONT) features |= ISA_mont_msk; - if (av & AV_SPARC_PAUSE) features |= ISA_pause_msk; - if (av & AV_SPARC_CBCOND) features |= ISA_cbcond_msk; - if (av & AV_SPARC_CRC32C) features |= ISA_crc32c_msk; - -#ifndef AV2_SPARC_FJATHPLUS -#define AV2_SPARC_FJATHPLUS 0x00000001 // Fujitsu Athena+ insns -#endif -#ifndef AV2_SPARC_VIS3B -#define AV2_SPARC_VIS3B 0x00000002 // VIS3 present on multiple chips -#endif -#ifndef AV2_SPARC_ADI -#define AV2_SPARC_ADI 0x00000004 // Application Data Integrity -#endif -#ifndef AV2_SPARC_SPARC5 -#define AV2_SPARC_SPARC5 0x00000008 // The 29 new fp and sub instructions -#endif -#ifndef AV2_SPARC_MWAIT -#define AV2_SPARC_MWAIT 0x00000010 // mwait instruction and load/monitor ASIs -#endif -#ifndef AV2_SPARC_XMPMUL -#define AV2_SPARC_XMPMUL 0x00000020 // XOR multiple precision multiply -#endif -#ifndef AV2_SPARC_XMONT -#define AV2_SPARC_XMONT 0x00000040 // XOR Montgomery mult/sqr instructions -#endif -#ifndef AV2_SPARC_PAUSE_NSEC -#define AV2_SPARC_PAUSE_NSEC 0x00000080 // pause instruction with support for nsec timings -#endif -#ifndef AV2_SPARC_VAMASK -#define AV2_SPARC_VAMASK 0x00000100 // Virtual Address masking -#endif - -#ifndef AV2_SPARC_SPARC6 -#define AV2_SPARC_SPARC6 0x00000200 // REVB*, FPSLL*, RDENTROPY, LDM* and STM* -#endif -#ifndef AV2_SPARC_DICTUNP -#define AV2_SPARC_DICTUNP 0x00002000 // Dictionary unpack instruction -#endif -#ifndef AV2_SPARC_FPCMPSHL -#define AV2_SPARC_FPCMPSHL 0x00004000 // Partition compare with shifted result -#endif -#ifndef AV2_SPARC_RLE -#define AV2_SPARC_RLE 0x00008000 // Run-length encoded burst and length -#endif -#ifndef AV2_SPARC_SHA3 -#define AV2_SPARC_SHA3 0x00010000 // SHA3 instructions -#endif -#ifndef AV2_SPARC_FJATHPLUS2 -#define AV2_SPARC_FJATHPLUS2 0x00020000 // Fujitsu Athena++ insns -#endif -#ifndef AV2_SPARC_VIS3C -#define AV2_SPARC_VIS3C 0x00040000 // Subset of VIS3 insns provided by Athena++ -#endif -#ifndef AV2_SPARC_SPARC5B -#define AV2_SPARC_SPARC5B 0x00080000 // subset of SPARC5 insns (fpadd8, fpsub8) -#endif -#ifndef AV2_SPARC_MME -#define AV2_SPARC_MME 0x00100000 // Misaligned Mitigation Enable -#endif - - if (avn > 1) { - uint32_t av2 = avs[AV_HW2_IDX]; - - if (av2 & AV2_SPARC_FJATHPLUS) features |= ISA_fjathplus_msk; - if (av2 & AV2_SPARC_VIS3B) features |= ISA_vis3b_msk; - if (av2 & AV2_SPARC_ADI) features |= ISA_adi_msk; - if (av2 & AV2_SPARC_SPARC5) features |= ISA_sparc5_msk; - if (av2 & AV2_SPARC_MWAIT) features |= ISA_mwait_msk; - if (av2 & AV2_SPARC_XMPMUL) features |= ISA_xmpmul_msk; - if (av2 & AV2_SPARC_XMONT) features |= ISA_xmont_msk; - if (av2 & AV2_SPARC_PAUSE_NSEC) features |= ISA_pause_nsec_msk; - if (av2 & AV2_SPARC_VAMASK) features |= ISA_vamask_msk; - - if (av2 & AV2_SPARC_SPARC6) features |= ISA_sparc6_msk; - if (av2 & AV2_SPARC_DICTUNP) features |= ISA_dictunp_msk; - if (av2 & AV2_SPARC_FPCMPSHL) features |= ISA_fpcmpshl_msk; - if (av2 & AV2_SPARC_RLE) features |= ISA_rle_msk; - if (av2 & AV2_SPARC_SHA3) features |= ISA_sha3_msk; - if (av2 & AV2_SPARC_FJATHPLUS2) features |= ISA_fjathplus2_msk; - if (av2 & AV2_SPARC_VIS3C) features |= ISA_vis3c_msk; - if (av2 & AV2_SPARC_SPARC5B) features |= ISA_sparc5b_msk; - if (av2 & AV2_SPARC_MME) features |= ISA_mme_msk; - } - - _features = features; // ISA feature set completed, update state. - - Sysinfo machine(SI_MACHINE); - - bool is_sun4v = machine.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+/++ - bool is_sun4u = machine.match("sun4u"); // All other Fujitsu - - // Handle Athena+/++ conservatively (simply because we are lacking info.). - - bool an_athena = has_athena_plus() || has_athena_plus2(); - bool do_sun4v = is_sun4v && !an_athena; - bool do_sun4u = is_sun4u || an_athena; - - uint64_t synthetic = 0; - - if (do_sun4v) { - // Indirect and direct branches are equally fast. - synthetic = CPU_fast_ind_br_msk; - // Fast IDIV, BIS and LD available on Niagara Plus. - if (has_vis2()) { - synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk); - // ...on Core C4 however, we prefer not to use BIS. - if (!has_sparc5()) { - synthetic |= CPU_fast_bis_msk; - } - } - // SPARC Core C3 supports fast RDPC and block zeroing. - if (has_ima()) { - synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk); - } - // SPARC Core C3 and C4 have slow CMOVE. - if (!has_ima()) { - synthetic |= CPU_fast_cmove_msk; - } - } else if (do_sun4u) { - // SPARC64 only have fast IDIV and RDPC. - synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk); - } else { - log_info(os, cpu)("Unable to derive CPU features: %s", machine.value()); - } - - _features += synthetic; // Including CPU derived/synthetic features. - - Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); - Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); - - // Require both Sysconf requests to be valid or use fall-back. - - if (l1_dcache_line_size.valid() && - l2_dcache_line_size.valid()) { - _L1_data_cache_line_size = l1_dcache_line_size.value(); - _L2_data_cache_line_size = l2_dcache_line_size.value(); - } else { - // Otherwise figure out the cache line sizes using PICL. - PICL picl(is_sun4u, is_sun4v); - _L1_data_cache_line_size = picl.L1_data_cache_line_size(); - _L2_data_cache_line_size = picl.L2_data_cache_line_size(); - } -} diff --git a/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 1999, 2015, 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "runtime/os.hpp" - -void MacroAssembler::int3() { - push(rax); - push(rdx); - push(rcx); - call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint))); - pop(rcx); - pop(rdx); - pop(rax); -} diff --git a/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP - -// For Sun Studio - implementation is in solaris_x86_64.il. - -extern "C" { - int32_t _Atomic_add(int32_t add_value, volatile int32_t* dest); - int64_t _Atomic_add_long(int64_t add_value, volatile int64_t* dest); - - int32_t _Atomic_xchg(int32_t exchange_value, volatile int32_t* dest); - int8_t _Atomic_cmpxchg_byte(int8_t exchange_value, volatile int8_t* dest, - int8_t compare_value); - int32_t _Atomic_cmpxchg(int32_t exchange_value, volatile int32_t* dest, - int32_t compare_value); - int64_t _Atomic_cmpxchg_long(int64_t exchange_value, volatile int64_t* dest, - int64_t compare_value); -} - -template -struct Atomic::PlatformAdd { - template - D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const; - - template - D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { - return add_and_fetch(dest, add_value, order) - add_value; - } -}; - -// Not using add_using_helper; see comment for cmpxchg. -template<> -template -inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(I)); - STATIC_ASSERT(4 == sizeof(D)); - return PrimitiveConversions::cast( - _Atomic_add(PrimitiveConversions::cast(add_value), - reinterpret_cast(dest))); -} - -// Not using add_using_helper; see comment for cmpxchg. -template<> -template -inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(I)); - STATIC_ASSERT(8 == sizeof(D)); - return PrimitiveConversions::cast( - _Atomic_add_long(PrimitiveConversions::cast(add_value), - reinterpret_cast(dest))); -} - -template<> -template -inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(T)); - return PrimitiveConversions::cast( - _Atomic_xchg(PrimitiveConversions::cast(exchange_value), - reinterpret_cast(dest))); -} - -extern "C" int64_t _Atomic_xchg_long(int64_t exchange_value, volatile int64_t* dest); - -template<> -template -inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - return PrimitiveConversions::cast( - _Atomic_xchg_long(PrimitiveConversions::cast(exchange_value), - reinterpret_cast(dest))); -} - -// Not using cmpxchg_using_helper here, because some configurations of -// Solaris compiler don't deal well with passing a "defined in .il" -// function as an argument. We *should* switch to using gcc-style -// inline assembly, but attempting to do so with Studio 12.4 ran into -// segfaults. - -template<> -template -inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(1 == sizeof(T)); - return PrimitiveConversions::cast( - _Atomic_cmpxchg_byte(PrimitiveConversions::cast(exchange_value), - reinterpret_cast(dest), - PrimitiveConversions::cast(compare_value))); -} - -template<> -template -inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(4 == sizeof(T)); - return PrimitiveConversions::cast( - _Atomic_cmpxchg(PrimitiveConversions::cast(exchange_value), - reinterpret_cast(dest), - PrimitiveConversions::cast(compare_value))); -} - -template<> -template -inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, - T compare_value, - T exchange_value, - atomic_memory_order order) const { - STATIC_ASSERT(8 == sizeof(T)); - return PrimitiveConversions::cast( - _Atomic_cmpxchg_long(PrimitiveConversions::cast(exchange_value), - reinterpret_cast(dest), - PrimitiveConversions::cast(compare_value))); -} - -#endif // OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.inline.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.inline.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 1998, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_INLINE_HPP -#define OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_INLINE_HPP - -// For Sun Studio - implementation is in solaris_i486.il. -// For gcc - implementation is just below. -extern "C" u2 _raw_swap_u2(u2 x); -extern "C" u4 _raw_swap_u4(u4 x); -#ifdef AMD64 -extern "C" u8 _raw_swap_u8(u8 x); -#else -extern "C" u8 _raw_swap_u8(u4 x, u4 y); -#endif // AMD64 - -// Efficient swapping of data bytes from Java byte -// ordering to native byte ordering and vice versa. -inline u2 Bytes::swap_u2(u2 x) { - return _raw_swap_u2(x); -} - -inline u4 Bytes::swap_u4(u4 x) { - return _raw_swap_u4(x); -} - -inline u8 Bytes::swap_u8(u8 x) { -#ifdef AMD64 - return _raw_swap_u8(x); -#else - return swap_u8_base(*(u4*)&x, *(((u4*)&x)+1)); -#endif // AMD64 - -} - -#ifndef AMD64 -// Helper function for swap_u8 -inline u8 Bytes::swap_u8_base(u4 x, u4 y) { - return _raw_swap_u8(x, y); -} -#endif // !AMD64 - -#endif // OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.inline.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.inline.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_INLINE_HPP -#define OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_INLINE_HPP - -static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - (void)memmove(to, from, count * HeapWordSize); -} - -static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { -#ifndef AMD64 - (void)memcpy(to, from, count * HeapWordSize); -#else - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: - (void)memcpy(to, from, count * HeapWordSize); - break; - } -#endif // AMD64 -} - -static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { - switch (count) { - case 8: to[7] = from[7]; - case 7: to[6] = from[6]; - case 6: to[5] = from[5]; - case 5: to[4] = from[4]; - case 4: to[3] = from[3]; - case 3: to[2] = from[2]; - case 2: to[1] = from[1]; - case 1: to[0] = from[0]; - case 0: break; - default: while (count-- > 0) { - *to++ = *from++; - } - break; - } -} - -static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - (void)memmove(to, from, count * HeapWordSize); -} - -static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { - pd_disjoint_words(from, to, count); -} - -static void pd_conjoint_bytes(const void* from, void* to, size_t count) { -#ifdef AMD64 - (void)memmove(to, from, count); -#else - _Copy_conjoint_bytes(from, to, count); -#endif // AMD64 -} - -static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { - pd_conjoint_bytes(from, to, count); -} - -static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { - _Copy_conjoint_jshorts_atomic(from, to, count); -} - -static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { - _Copy_conjoint_jints_atomic(from, to, count); -} - -static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { - // Guarantee use of fild/fistp or xmm regs via some asm code, because compilers won't. - _Copy_conjoint_jlongs_atomic(from, to, count); -} - -static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { -#ifdef AMD64 - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#else - _Copy_conjoint_jints_atomic((const jint*)from, (jint*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_bytes(from, to, count); -} - -static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jshorts(from, to, count); -} - -static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { - _Copy_arrayof_conjoint_jints(from, to, count); -} - -static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); -#endif // AMD64 -} - -static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { -#ifdef AMD64 - assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); - _Copy_arrayof_conjoint_jlongs(from, to, count); -#else - assert(BytesPerInt == BytesPerOop, "jints and oops must be the same size"); - _Copy_arrayof_conjoint_jints(from, to, count); -#endif // AMD64 -} - -#endif // OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_COUNT_TRAILING_ZEROS_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_COUNT_TRAILING_ZEROS_SOLARIS_X86_HPP - -#include "utilities/globalDefinitions.hpp" - -inline unsigned count_trailing_zeros(uintx x) { - assert(x != 0, "precondition"); - uintx result; - __asm__(" rep bsfq %1, %0" : "=r" (result) : "rm" (x)); - return result; -} - -#endif // OS_CPU_SOLARIS_X86_COUNT_TRAILING_ZEROS_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP - -// Sets the default values for platform dependent flags used by the runtime system. -// (see globals.hpp) - -define_pd_global(bool, DontYieldALot, true); // Determined in the design center -#ifdef AMD64 -define_pd_global(intx, CompilerThreadStackSize, 1024); -define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default -define_pd_global(intx, VMThreadStackSize, 1024); -define_pd_global(size_t, JVMInvokeMethodSlack, 8*K); -#else -define_pd_global(intx, CompilerThreadStackSize, 512); -// ThreadStackSize 320 allows a couple of test cases to run while -// keeping the number of threads that can be created high. -define_pd_global(intx, ThreadStackSize, 320); -define_pd_global(intx, VMThreadStackSize, 512); -define_pd_global(size_t, JVMInvokeMethodSlack, 10*K); -#endif // AMD64 - - -// Used on 64 bit platforms for UseCompressedOops base address -define_pd_global(size_t, HeapBaseMinAddress, 2*G); - -#endif // OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP - -// Included in orderAccess.hpp header file. - -// Compiler version last used for testing: solaris studio 12u3 -// Please update this information when this file changes - -// Implementation of class OrderAccess. - -// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions -inline void compiler_barrier() { - __asm__ volatile ("" : : : "memory"); -} - -inline void OrderAccess::loadload() { compiler_barrier(); } -inline void OrderAccess::storestore() { compiler_barrier(); } -inline void OrderAccess::loadstore() { compiler_barrier(); } -inline void OrderAccess::storeload() { fence(); } - -inline void OrderAccess::acquire() { compiler_barrier(); } -inline void OrderAccess::release() { compiler_barrier(); } - -inline void OrderAccess::fence() { -#ifdef AMD64 - __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); -#else - __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory"); -#endif - compiler_barrier(); -} - -inline void OrderAccess::cross_modify_fence() { - int idx = 0; - __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory"); -} - -#endif // OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Copyright (c) 1999, 2020, 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. - * - */ - -// no precompiled headers -#include "jvm.h" -#include "asm/macroAssembler.hpp" -#include "classfile/classLoader.hpp" -#include "classfile/systemDictionary.hpp" -#include "classfile/vmSymbols.hpp" -#include "code/codeCache.hpp" -#include "code/icBuffer.hpp" -#include "code/vtableStubs.hpp" -#include "interpreter/interpreter.hpp" -#include "logging/log.hpp" -#include "memory/allocation.inline.hpp" -#include "os_share_solaris.hpp" -#include "prims/jniFastGetField.hpp" -#include "prims/jvm_misc.hpp" -#include "runtime/arguments.hpp" -#include "runtime/extendedPC.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" -#include "runtime/java.hpp" -#include "runtime/javaCalls.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/osThread.hpp" -#include "runtime/safepointMechanism.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "runtime/thread.inline.hpp" -#include "runtime/timer.hpp" -#include "utilities/align.hpp" -#include "utilities/events.hpp" -#include "utilities/vmError.hpp" - -// put OS-includes here -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include // see comment in - -#ifndef AMD64 -// QQQ seems useless at this point -# define _STRUCTURED_PROC 1 // this gets us the new structured proc interfaces of 5.6 & later -#endif // AMD64 -# include // see comment in - - -#define MAX_PATH (2 * K) - -// Minimum usable stack sizes required to get to user code. Space for -// HotSpot guard pages is added later. -#ifdef _LP64 -// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler -// threads requires a large stack with the Solaris Studio C++ compiler version 5.13 -// and product VM builds (debug builds require significantly less stack space). -size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K; -size_t os::Posix::_java_thread_min_stack_allowed = 48 * K; -size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K; -#else -size_t os::Posix::_compiler_thread_min_stack_allowed = 32 * K; -size_t os::Posix::_java_thread_min_stack_allowed = 32 * K; -size_t os::Posix::_vm_internal_thread_min_stack_allowed = 64 * K; -#endif // _LP64 - -#ifdef AMD64 -#define REG_SP REG_RSP -#define REG_PC REG_RIP -#define REG_FP REG_RBP -#else -#define REG_SP UESP -#define REG_PC EIP -#define REG_FP EBP -// 4900493 counter to prevent runaway LDTR refresh attempt - -static volatile int ldtr_refresh = 0; -// the libthread instruction that faults because of the stale LDTR - -static const unsigned char movlfs[] = { 0x8e, 0xe0 // movl %eax,%fs - }; -#endif // AMD64 - -char* os::non_memory_address_word() { - // Must never look like an address returned by reserve_memory, - // even in its subfields (as defined by the CPU immediate fields, - // if the CPU splits constants across multiple instructions). - return (char*) -1; -} - -// -// Validate a ucontext retrieved from walking a uc_link of a ucontext. -// There are issues with libthread giving out uc_links for different threads -// on the same uc_link chain and bad or circular links. -// -bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) { - if (valid >= suspect || - valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags || - valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp || - valid->uc_stack.ss_size != suspect->uc_stack.ss_size) { - DEBUG_ONLY(tty->print_cr("valid_ucontext: failed test 1");) - return false; - } - - if (thread->is_Java_thread()) { - if (!thread->is_in_full_stack_checked((address)suspect)) { - DEBUG_ONLY(tty->print_cr("valid_ucontext: uc_link not in thread stack");) - return false; - } - if (!thread->is_in_full_stack_checked((address) suspect->uc_mcontext.gregs[REG_SP])) { - DEBUG_ONLY(tty->print_cr("valid_ucontext: stackpointer not in thread stack");) - return false; - } - } - return true; -} - -// We will only follow one level of uc_link since there are libthread -// issues with ucontext linking and it is better to be safe and just -// let caller retry later. -const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, - const ucontext_t *uc) { - - const ucontext_t *retuc = NULL; - - if (uc != NULL) { - if (uc->uc_link == NULL) { - // cannot validate without uc_link so accept current ucontext - retuc = uc; - } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { - // first ucontext is valid so try the next one - uc = uc->uc_link; - if (uc->uc_link == NULL) { - // cannot validate without uc_link so accept current ucontext - retuc = uc; - } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { - // the ucontext one level down is also valid so return it - retuc = uc; - } - } - } - return retuc; -} - -// Assumes ucontext is valid -ExtendedPC os::Solaris::ucontext_get_ExtendedPC(const ucontext_t *uc) { - return ExtendedPC((address)uc->uc_mcontext.gregs[REG_PC]); -} - -void os::Solaris::ucontext_set_pc(ucontext_t* uc, address pc) { - uc->uc_mcontext.gregs [REG_PC] = (greg_t) pc; -} - -// Assumes ucontext is valid -intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) { - return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; -} - -// Assumes ucontext is valid -intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) { - return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; -} - -address os::Solaris::ucontext_get_pc(const ucontext_t *uc) { - return (address) uc->uc_mcontext.gregs[REG_PC]; -} - -// For Forte Analyzer AsyncGetCallTrace profiling support - thread -// is currently interrupted by SIGPROF. -// -// The difference between this and os::fetch_frame_from_context() is that -// here we try to skip nested signal frames. -// This method is also used for stack overflow signal handling. -ExtendedPC os::Solaris::fetch_frame_from_ucontext(Thread* thread, - const ucontext_t* uc, intptr_t** ret_sp, intptr_t** ret_fp) { - - assert(thread != NULL, "just checking"); - assert(ret_sp != NULL, "just checking"); - assert(ret_fp != NULL, "just checking"); - - const ucontext_t *luc = os::Solaris::get_valid_uc_in_signal_handler(thread, uc); - return os::fetch_frame_from_context(luc, ret_sp, ret_fp); -} - -ExtendedPC os::fetch_frame_from_context(const void* ucVoid, - intptr_t** ret_sp, intptr_t** ret_fp) { - - ExtendedPC epc; - const ucontext_t *uc = (const ucontext_t*)ucVoid; - - if (uc != NULL) { - epc = os::Solaris::ucontext_get_ExtendedPC(uc); - if (ret_sp) *ret_sp = os::Solaris::ucontext_get_sp(uc); - if (ret_fp) *ret_fp = os::Solaris::ucontext_get_fp(uc); - } else { - // construct empty ExtendedPC for return value checking - epc = ExtendedPC(NULL); - if (ret_sp) *ret_sp = (intptr_t *)NULL; - if (ret_fp) *ret_fp = (intptr_t *)NULL; - } - - return epc; -} - -frame os::fetch_frame_from_context(const void* ucVoid) { - intptr_t* sp; - intptr_t* fp; - ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); - return frame(sp, fp, epc.pc()); -} - -frame os::fetch_frame_from_ucontext(Thread* thread, void* ucVoid) { - intptr_t* sp; - intptr_t* fp; - ExtendedPC epc = os::Solaris::fetch_frame_from_ucontext(thread, (ucontext_t*)ucVoid, &sp, &fp); - return frame(sp, fp, epc.pc()); -} - -bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { - address pc = (address) os::Solaris::ucontext_get_pc(uc); - if (Interpreter::contains(pc)) { - // interpreter performs stack banging after the fixed frame header has - // been generated while the compilers perform it before. To maintain - // semantic consistency between interpreted and compiled frames, the - // method returns the Java sender of the current frame. - *fr = os::fetch_frame_from_ucontext(thread, uc); - if (!fr->is_first_java_frame()) { - // get_frame_at_stack_banging_point() is only called when we - // have well defined stacks so java_sender() calls do not need - // to assert safe_for_sender() first. - *fr = fr->java_sender(); - } - } else { - // more complex code with compiled code - assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); - CodeBlob* cb = CodeCache::find_blob(pc); - if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { - // Not sure where the pc points to, fallback to default - // stack overflow handling - return false; - } else { - // in compiled code, the stack banging is performed just after the return pc - // has been pushed on the stack - intptr_t* fp = os::Solaris::ucontext_get_fp(uc); - intptr_t* sp = os::Solaris::ucontext_get_sp(uc); - *fr = frame(sp + 1, fp, (address)*sp); - if (!fr->is_java_frame()) { - // See java_sender() comment above. - *fr = fr->java_sender(); - } - } - } - assert(fr->is_java_frame(), "Safety check"); - return true; -} - -frame os::get_sender_for_C_frame(frame* fr) { - return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); -} - -extern "C" intptr_t *_get_current_sp(); // in .il file - -address os::current_stack_pointer() { - return (address)_get_current_sp(); -} - -extern "C" intptr_t *_get_current_fp(); // in .il file - -frame os::current_frame() { - intptr_t* fp = _get_current_fp(); // it's inlined so want current fp - // fp is for os::current_frame. We want the fp for our caller. - frame myframe((intptr_t*)os::current_stack_pointer(), - (intptr_t*)fp, - CAST_FROM_FN_PTR(address, os::current_frame)); - frame caller_frame = os::get_sender_for_C_frame(&myframe); - - if (os::is_first_C_frame(&caller_frame)) { - // stack is not walkable - frame ret; // This will be a null useless frame - return ret; - } else { - // return frame for our caller's caller - return os::get_sender_for_C_frame(&caller_frame); - } -} - -#ifndef AMD64 - -// Detecting SSE support by OS -// From solaris_i486.s -extern "C" bool sse_check(); -extern "C" bool sse_unavailable(); - -enum { SSE_UNKNOWN, SSE_NOT_SUPPORTED, SSE_SUPPORTED}; -static int sse_status = SSE_UNKNOWN; - - -static void check_for_sse_support() { - if (!VM_Version::supports_sse()) { - sse_status = SSE_NOT_SUPPORTED; - return; - } - // looking for _sse_hw in libc.so, if it does not exist or - // the value (int) is 0, OS has no support for SSE - int *sse_hwp; - void *h; - - if ((h=dlopen("/usr/lib/libc.so", RTLD_LAZY)) == NULL) { - //open failed, presume no support for SSE - sse_status = SSE_NOT_SUPPORTED; - return; - } - if ((sse_hwp = (int *)dlsym(h, "_sse_hw")) == NULL) { - sse_status = SSE_NOT_SUPPORTED; - } else if (*sse_hwp == 0) { - sse_status = SSE_NOT_SUPPORTED; - } - dlclose(h); - - if (sse_status == SSE_UNKNOWN) { - bool (*try_sse)() = (bool (*)())sse_check; - sse_status = (*try_sse)() ? SSE_SUPPORTED : SSE_NOT_SUPPORTED; - } - -} - -#endif // AMD64 - -bool os::supports_sse() { -#ifdef AMD64 - return true; -#else - if (sse_status == SSE_UNKNOWN) - check_for_sse_support(); - return sse_status == SSE_SUPPORTED; -#endif // AMD64 -} - -bool os::is_allocatable(size_t bytes) { -#ifdef AMD64 - return true; -#else - - if (bytes < 2 * G) { - return true; - } - - char* addr = reserve_memory(bytes, NULL); - - if (addr != NULL) { - release_memory(addr, bytes); - } - - return addr != NULL; -#endif // AMD64 - -} - -extern "C" JNIEXPORT int -JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - -#ifndef AMD64 - if (sig == SIGILL && info->si_addr == (caddr_t)sse_check) { - // the SSE instruction faulted. supports_sse() need return false. - uc->uc_mcontext.gregs[EIP] = (greg_t)sse_unavailable; - return true; - } -#endif // !AMD64 - - Thread* t = Thread::current_or_null_safe(); - - // Must do this before SignalHandlerMark, if crash protection installed we will longjmp away - // (no destructors can be run) - os::ThreadCrashProtection::check_crash_protection(sig, t); - - SignalHandlerMark shm(t); - - if(sig == SIGPIPE || sig == SIGXFSZ) { - if (os::Solaris::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - - if (os::Solaris::signal_handlers_are_installed) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = (JavaThread*)t; - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } - - if (sig == ASYNC_SIGNAL) { - if(thread || vmthread){ - OSThread::SR_handler(t, uc); - return true; - } else if (os::Solaris::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // If ASYNC_SIGNAL not chained, and this is a non-vm and - // non-java thread - return true; - } - } - - if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { - // can't decode this kind of signal - info = NULL; - } else { - assert(sig == info->si_signo, "bad siginfo"); - } - - // decide if this trap can be handled by a stub - address stub = NULL; - - address pc = NULL; - - //%note os_trap_1 - if (info != NULL && uc != NULL && thread != NULL) { - // factor me: getPCfromContext - pc = (address) uc->uc_mcontext.gregs[REG_PC]; - - if (StubRoutines::is_safefetch_fault(pc)) { - os::Solaris::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return true; - } - - // Handle ALL stack overflow variations here - if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { - address addr = (address) info->si_addr; - if (thread->in_stack_yellow_reserved_zone(addr)) { - if (thread->thread_state() == _thread_in_Java) { - if (thread->in_stack_reserved_zone(addr)) { - frame fr; - if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) { - assert(fr.is_java_frame(), "Must be Java frame"); - frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); - if (activation.sp() != NULL) { - thread->disable_stack_reserved_zone(); - if (activation.is_interpreted_frame()) { - thread->set_reserved_stack_activation((address)( - activation.fp() + frame::interpreter_frame_initial_sp_offset)); - } else { - thread->set_reserved_stack_activation((address)activation.unextended_sp()); - } - return true; - } - } - } - // Throw a stack overflow exception. Guard pages will be reenabled - // while unwinding the stack. - thread->disable_stack_yellow_reserved_zone(); - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); - } else { - // Thread was in the vm or native code. Return and try to finish. - thread->disable_stack_yellow_reserved_zone(); - return true; - } - } else if (thread->in_stack_red_zone(addr)) { - // Fatal red zone violation. Disable the guard pages and fall through - // to handle_unexpected_exception way down below. - thread->disable_stack_red_zone(); - tty->print_raw_cr("An irrecoverable stack overflow has occurred."); - } - } - - if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { - // Verify that OS save/restore AVX registers. - stub = VM_Version::cpuinfo_cont_addr(); - } - - if (thread->thread_state() == _thread_in_vm || - thread->thread_state() == _thread_in_native) { - if (sig == SIGBUS && info->si_code == BUS_OBJERR && thread->doing_unsafe_access()) { - address next_pc = Assembler::locate_next_instruction(pc); - if (UnsafeCopyMemory::contains_pc(pc)) { - next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); - } - stub = SharedRuntime::handle_unsafe_access(thread, next_pc); - } - } - - if (thread->thread_state() == _thread_in_Java) { - // Support Safepoint Polling - if ( sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) { - stub = SharedRuntime::get_poll_stub(pc); - } - else if (sig == SIGBUS && info->si_code == BUS_OBJERR) { - // BugId 4454115: A read from a MappedByteBuffer can fault - // here if the underlying file has been truncated. - // Do not crash the VM in such a case. - CodeBlob* cb = CodeCache::find_blob_unsafe(pc); - if (cb != NULL) { - CompiledMethod* nm = cb->as_compiled_method_or_null(); - bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc); - if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) { - address next_pc = Assembler::locate_next_instruction(pc); - if (is_unsafe_arraycopy) { - next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); - } - stub = SharedRuntime::handle_unsafe_access(thread, next_pc); - } - } - } - else - if (sig == SIGFPE && info->si_code == FPE_INTDIV) { - // integer divide by zero - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - } -#ifndef AMD64 - else if (sig == SIGFPE && info->si_code == FPE_FLTDIV) { - // floating-point divide by zero - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); - } - else if (sig == SIGFPE && info->si_code == FPE_FLTINV) { - // The encoding of D2I in i486.ad can cause an exception prior - // to the fist instruction if there was an invalid operation - // pending. We want to dismiss that exception. From the win_32 - // side it also seems that if it really was the fist causing - // the exception that we do the d2i by hand with different - // rounding. Seems kind of weird. QQQ TODO - // Note that we take the exception at the NEXT floating point instruction. - if (pc[0] == 0xDB) { - assert(pc[0] == 0xDB, "not a FIST opcode"); - assert(pc[1] == 0x14, "not a FIST opcode"); - assert(pc[2] == 0x24, "not a FIST opcode"); - return true; - } else { - assert(pc[-3] == 0xDB, "not an flt invalid opcode"); - assert(pc[-2] == 0x14, "not an flt invalid opcode"); - assert(pc[-1] == 0x24, "not an flt invalid opcode"); - } - } - else if (sig == SIGFPE ) { - tty->print_cr("caught SIGFPE, info 0x%x.", info->si_code); - } -#endif // !AMD64 - - // QQQ It doesn't seem that we need to do this on x86 because we should be able - // to return properly from the handler without this extra stuff on the back side. - - else if (sig == SIGSEGV && info->si_code > 0 && - MacroAssembler::uses_implicit_null_check(info->si_addr)) { - // Determination of interpreter/vtable stub/compiled code null exception - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); - } - } - - // jni_fast_GetField can trap at certain pc's if a GC kicks in - // and the heap gets shrunk before the field access. - if ((sig == SIGSEGV) || (sig == SIGBUS)) { - address addr = JNI_FastGetField::find_slowcase_pc(pc); - if (addr != (address)-1) { - stub = addr; - } - } - } - - // Execution protection violation - // - // Preventative code for future versions of Solaris which may - // enable execution protection when running the 32-bit VM on AMD64. - // - // This should be kept as the last step in the triage. We don't - // have a dedicated trap number for a no-execute fault, so be - // conservative and allow other handlers the first shot. - // - // Note: We don't test that info->si_code == SEGV_ACCERR here. - // this si_code is so generic that it is almost meaningless; and - // the si_code for this condition may change in the future. - // Furthermore, a false-positive should be harmless. - if (UnguardOnExecutionViolation > 0 && - (sig == SIGSEGV || sig == SIGBUS) && - uc->uc_mcontext.gregs[TRAPNO] == T_PGFLT) { // page fault - int page_size = os::vm_page_size(); - address addr = (address) info->si_addr; - address pc = (address) uc->uc_mcontext.gregs[REG_PC]; - // Make sure the pc and the faulting address are sane. - // - // If an instruction spans a page boundary, and the page containing - // the beginning of the instruction is executable but the following - // page is not, the pc and the faulting address might be slightly - // different - we still want to unguard the 2nd page in this case. - // - // 15 bytes seems to be a (very) safe value for max instruction size. - bool pc_is_near_addr = - (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); - bool instr_spans_page_boundary = - (align_down((intptr_t) pc ^ (intptr_t) addr, - (intptr_t) page_size) > 0); - - if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { - static volatile address last_addr = - (address) os::non_memory_address_word(); - - // In conservative mode, don't unguard unless the address is in the VM - if (addr != last_addr && - (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { - - // Make memory rwx and retry - address page_start = align_down(addr, page_size); - bool res = os::protect_memory((char*) page_start, page_size, - os::MEM_PROT_RWX); - - log_debug(os)("Execution protection violation " - "at " INTPTR_FORMAT - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), - p2i(page_start), (res ? "success" : "failed"), errno); - stub = pc; - - // Set last_addr so if we fault again at the same address, we don't end - // up in an endless loop. - // - // There are two potential complications here. Two threads trapping at - // the same address at the same time could cause one of the threads to - // think it already unguarded, and abort the VM. Likely very rare. - // - // The other race involves two threads alternately trapping at - // different addresses and failing to unguard the page, resulting in - // an endless loop. This condition is probably even more unlikely than - // the first. - // - // Although both cases could be avoided by using locks or thread local - // last_addr, these solutions are unnecessary complication: this - // handler is a best-effort safety net, not a complete solution. It is - // disabled by default and should only be used as a workaround in case - // we missed any no-execute-unsafe VM code. - - last_addr = addr; - } - } - } - - if (stub != NULL) { - // save all thread context in case we need to restore it - - if (thread != NULL) thread->set_saved_exception_pc(pc); - // 12/02/99: On Sparc it appears that the full context is also saved - // but as yet, no one looks at or restores that saved context - os::Solaris::ucontext_set_pc(uc, stub); - return true; - } - - // signal-chaining - if (os::Solaris::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (!os::Solaris::libjsig_is_loaded) { - struct sigaction oldAct; - sigaction(sig, (struct sigaction *)0, &oldAct); - if (oldAct.sa_sigaction != signalHandler) { - void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*, oldAct.sa_sigaction) - : CAST_FROM_FN_PTR(void*, oldAct.sa_handler); - warning("Unexpected Signal %d occurred under user-defined signal handler %#lx", sig, (long)sighand); - } - } - - if (pc == NULL && uc != NULL) { - pc = (address) uc->uc_mcontext.gregs[REG_PC]; - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - // Determine which sort of error to throw. Out of swap may signal - // on the thread stack, which could get a mapping error when touched. - address addr = (address) info->si_addr; - if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) { - vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack."); - } - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); - return false; -} - -void os::print_context(outputStream *st, const void *context) { - if (context == NULL) return; - - const ucontext_t *uc = (const ucontext_t*)context; - st->print_cr("Registers:"); -#ifdef AMD64 - st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); - st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); - st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); - st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); - st->cr(); - st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); - st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); - st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); - st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); - st->cr(); - st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); - st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); - st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); - st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); - st->cr(); - st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); - st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); - st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); - st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); - st->cr(); - st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); - st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]); -#else - st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); - st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); - st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]); - st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]); - st->cr(); - st->print( "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]); - st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]); - st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]); - st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]); - st->cr(); - st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]); - st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]); -#endif // AMD64 - st->cr(); - st->cr(); - - intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); - st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); - print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t)); - st->cr(); - - // Note: it may be unsafe to inspect memory near pc. For example, pc may - // point to garbage if entry point in an nmethod is corrupted. Leave - // this at the end, and hope for the best. - ExtendedPC epc = os::Solaris::ucontext_get_ExtendedPC(uc); - address pc = epc.pc(); - print_instructions(st, pc, sizeof(char)); - st->cr(); -} - -void os::print_register_info(outputStream *st, const void *context) { - if (context == NULL) return; - - const ucontext_t *uc = (const ucontext_t*)context; - - st->print_cr("Register to memory mapping:"); - st->cr(); - - // this is horrendously verbose but the layout of the registers in the - // context does not match how we defined our abstract Register set, so - // we can't just iterate through the gregs area - - // this is only for the "general purpose" registers - -#ifdef AMD64 - st->print("RAX="); print_location(st, uc->uc_mcontext.gregs[REG_RAX]); - st->print("RBX="); print_location(st, uc->uc_mcontext.gregs[REG_RBX]); - st->print("RCX="); print_location(st, uc->uc_mcontext.gregs[REG_RCX]); - st->print("RDX="); print_location(st, uc->uc_mcontext.gregs[REG_RDX]); - st->print("RSP="); print_location(st, uc->uc_mcontext.gregs[REG_RSP]); - st->print("RBP="); print_location(st, uc->uc_mcontext.gregs[REG_RBP]); - st->print("RSI="); print_location(st, uc->uc_mcontext.gregs[REG_RSI]); - st->print("RDI="); print_location(st, uc->uc_mcontext.gregs[REG_RDI]); - st->print("R8 ="); print_location(st, uc->uc_mcontext.gregs[REG_R8]); - st->print("R9 ="); print_location(st, uc->uc_mcontext.gregs[REG_R9]); - st->print("R10="); print_location(st, uc->uc_mcontext.gregs[REG_R10]); - st->print("R11="); print_location(st, uc->uc_mcontext.gregs[REG_R11]); - st->print("R12="); print_location(st, uc->uc_mcontext.gregs[REG_R12]); - st->print("R13="); print_location(st, uc->uc_mcontext.gregs[REG_R13]); - st->print("R14="); print_location(st, uc->uc_mcontext.gregs[REG_R14]); - st->print("R15="); print_location(st, uc->uc_mcontext.gregs[REG_R15]); -#else - st->print("EAX="); print_location(st, uc->uc_mcontext.gregs[EAX]); - st->print("EBX="); print_location(st, uc->uc_mcontext.gregs[EBX]); - st->print("ECX="); print_location(st, uc->uc_mcontext.gregs[ECX]); - st->print("EDX="); print_location(st, uc->uc_mcontext.gregs[EDX]); - st->print("ESP="); print_location(st, uc->uc_mcontext.gregs[UESP]); - st->print("EBP="); print_location(st, uc->uc_mcontext.gregs[EBP]); - st->print("ESI="); print_location(st, uc->uc_mcontext.gregs[ESI]); - st->print("EDI="); print_location(st, uc->uc_mcontext.gregs[EDI]); -#endif - - st->cr(); -} - - -#ifdef AMD64 -void os::Solaris::init_thread_fpu_state(void) { - // Nothing to do -} -#else -// From solaris_i486.s -extern "C" void fixcw(); - -void os::Solaris::init_thread_fpu_state(void) { - // Set fpu to 53 bit precision. This happens too early to use a stub. - fixcw(); -} - -// These routines are the initial value of atomic_xchg_entry(), -// atomic_cmpxchg_entry(), atomic_inc_entry() and fence_entry() -// until initialization is complete. -// TODO - replace with .il implementation when compiler supports it. - -typedef int32_t xchg_func_t (int32_t, volatile int32_t*); -typedef int32_t cmpxchg_func_t (int32_t, volatile int32_t*, int32_t); -typedef int64_t cmpxchg_long_func_t(int64_t, volatile int64_t*, int64_t); -typedef int32_t add_func_t (int32_t, volatile int32_t*); - -int32_t os::atomic_xchg_bootstrap(int32_t exchange_value, volatile int32_t* dest) { - // try to use the stub: - xchg_func_t* func = CAST_TO_FN_PTR(xchg_func_t*, StubRoutines::atomic_xchg_entry()); - - if (func != NULL) { - os::atomic_xchg_func = func; - return (*func)(exchange_value, dest); - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - int32_t old_value = *dest; - *dest = exchange_value; - return old_value; -} - -int32_t os::atomic_cmpxchg_bootstrap(int32_t exchange_value, volatile int32_t* dest, int32_t compare_value) { - // try to use the stub: - cmpxchg_func_t* func = CAST_TO_FN_PTR(cmpxchg_func_t*, StubRoutines::atomic_cmpxchg_entry()); - - if (func != NULL) { - os::atomic_cmpxchg_func = func; - return (*func)(exchange_value, dest, compare_value); - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - int32_t old_value = *dest; - if (old_value == compare_value) - *dest = exchange_value; - return old_value; -} - -int64_t os::atomic_cmpxchg_long_bootstrap(int64_t exchange_value, volatile int64_t* dest, int64_t compare_value) { - // try to use the stub: - cmpxchg_long_func_t* func = CAST_TO_FN_PTR(cmpxchg_long_func_t*, StubRoutines::atomic_cmpxchg_long_entry()); - - if (func != NULL) { - os::atomic_cmpxchg_long_func = func; - return (*func)(exchange_value, dest, compare_value); - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - int64_t old_value = *dest; - if (old_value == compare_value) - *dest = exchange_value; - return old_value; -} - -int32_t os::atomic_add_bootstrap(int32_t add_value, volatile int32_t* dest) { - // try to use the stub: - add_func_t* func = CAST_TO_FN_PTR(add_func_t*, StubRoutines::atomic_add_entry()); - - if (func != NULL) { - os::atomic_add_func = func; - return (*func)(add_value, dest); - } - assert(Threads::number_of_threads() == 0, "for bootstrap only"); - - return (*dest) += add_value; -} - -xchg_func_t* os::atomic_xchg_func = os::atomic_xchg_bootstrap; -cmpxchg_func_t* os::atomic_cmpxchg_func = os::atomic_cmpxchg_bootstrap; -cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap; -add_func_t* os::atomic_add_func = os::atomic_add_bootstrap; - -extern "C" void _solaris_raw_setup_fpu(address ptr); -void os::setup_fpu() { - address fpu_cntrl = StubRoutines::addr_fpu_cntrl_wrd_std(); - _solaris_raw_setup_fpu(fpu_cntrl); -} -#endif // AMD64 - -#ifndef PRODUCT -void os::verify_stack_alignment() { -#ifdef AMD64 - assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); -#endif -} -#endif - -int os::extra_bang_size_in_bytes() { - // JDK-8050147 requires the full cache line bang for x86. - return VM_Version::L1_line_size(); -} diff --git a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP - - // - // NOTE: we are back in class os here, not Solaris - // -#ifdef AMD64 - static void setup_fpu() {} -#else - static int32_t (*atomic_xchg_func) (int32_t, volatile int32_t*); - static int32_t (*atomic_cmpxchg_func) (int32_t, volatile int32_t*, int32_t); - static int64_t (*atomic_cmpxchg_long_func)(int64_t, volatile int64_t*, int64_t); - static int32_t (*atomic_add_func) (int32_t, volatile int32_t*); - - static int32_t atomic_xchg_bootstrap (int32_t, volatile int32_t*); - static int32_t atomic_cmpxchg_bootstrap (int32_t, volatile int32_t*, int32_t); - static int64_t atomic_cmpxchg_long_bootstrap(int64_t, volatile int64_t*, int64_t); - static int32_t atomic_add_bootstrap (int32_t, volatile int32_t*); - - static void setup_fpu(); -#endif // AMD64 - - static bool supports_sse(); - - static jlong rdtsc(); - - static bool is_allocatable(size_t bytes); - - // Used to register dynamic code cache area with the OS - // Note: Currently only used in 64 bit Windows implementations - static bool register_code_area(char *low, char *high) { return true; } - -#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2011, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP -#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP - -#include "runtime/os.hpp" - -extern "C" jlong _raw_rdtsc(); // In .il file - -inline jlong os::rdtsc() { return _raw_rdtsc(); } - -#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2003, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP -#define OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP - -#include "runtime/prefetch.hpp" - -extern "C" { - void _Prefetch_read (void *loc, intx interval); - void _Prefetch_write(void *loc, intx interval); -} - -inline void Prefetch::read (void *loc, intx interval) { -#ifdef AMD64 - _Prefetch_read(loc, interval); -#endif // AMD64 -} - -// Use of this method should be gated by VM_Version::has_prefetchw. -inline void Prefetch::write(void *loc, intx interval) { -#ifdef AMD64 - _Prefetch_write(loc, interval); -#endif // AMD64 -} - -#endif // OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il b/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright (c) 2004, 2015, 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 argument size of each inline directive is ignored by the compiler - // and is set to the number of arguments as documentation. - - // Get the raw thread ID from %gs:0 - .inline _raw_thread_id,0 - movq %fs:0, %rax - .end - - // Get current sp - .inline _get_current_sp,0 - .volatile - movq %rsp, %rax - .end - - // Get current fp - .inline _get_current_fp,0 - .volatile - movq %rbp, %rax - .end - - // Support for os::rdtsc() - .inline _raw_rdtsc,0 - rdtsc - salq $32, %rdx - orq %rdx, %rax - .end - - // Implementation of jint _Atomic_add(jint add_value, volatile jint* dest) - // used by Atomic::add(volatile jint* dest, jint add_value) - .inline _Atomic_add,2 - movl %edi, %eax // save add_value for return - lock - xaddl %edi, (%rsi) - addl %edi, %eax - .end - - // Implementation of jlong _Atomic_add(jlong add_value, volatile jlong* dest) - // used by Atomic::add(volatile jlong* dest, jint add_value) - .inline _Atomic_add_long,2 - movq %rdi, %rax // save add_value for return - lock - xaddq %rdi, (%rsi) - addq %rdi, %rax - .end - - // Implementation of jint _Atomic_xchg(jint exchange_value, volatile jint* dest) - // used by Atomic::xchg(volatile jint* dest, jint exchange_value) - .inline _Atomic_xchg,2 - xchgl (%rsi), %edi - movl %edi, %eax - .end - - // Implementation of jlong _Atomic_xchg(jlong exchange_value, volatile jlong* dest) - // used by Atomic::xchg(volatile jlong* dest, jlong exchange_value) - .inline _Atomic_xchg_long,2 - xchgq (%rsi), %rdi - movq %rdi, %rax - .end - - // Support for jbyte Atomic::cmpxchg(volatile jbyte *dest, - // jbyte compare_value, - // jbyte exchange_value) - .inline _Atomic_cmpxchg_byte,3 - movb %dl, %al // compare_value - lock - cmpxchgb %dil, (%rsi) - .end - - // Support for jint Atomic::cmpxchg(volatile jint *dest, - // int compare_value, - // jint exchange_value) - .inline _Atomic_cmpxchg,3 - movl %edx, %eax // compare_value - lock - cmpxchgl %edi, (%rsi) - .end - - // Support for jlong Atomic::cmpxchg(volatile jlong* dest, - // jlong compare_value, - // jlong exchange_value) - .inline _Atomic_cmpxchg_long,3 - movq %rdx, %rax // compare_value - lock - cmpxchgq %rdi, (%rsi) - .end - - // Support for u2 Bytes::swap_u2(u2 x) - .inline _raw_swap_u2,1 - movw %di, %ax - rorw $8, %ax - .end - - // Support for u4 Bytes::swap_u4(u4 x) - .inline _raw_swap_u4,1 - movl %edi, %eax - bswapl %eax - .end - - // Support for u8 Bytes::swap_u8(u8 x) - .inline _raw_swap_u8,1 - movq %rdi, %rax - bswapq %rax - .end - - // Support for void Prefetch::read - .inline _Prefetch_read,2 - prefetcht0 (%rdi, %rsi, 1) - .end - - // Support for void Prefetch::write - // We use prefetcht0 because em64t doesn't support prefetchw. - // prefetchw is a 3dnow instruction. - .inline _Prefetch_write,2 - prefetcht0 (%rdi, %rsi, 1) - .end diff --git a/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.s b/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.s deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.s +++ /dev/null @@ -1,386 +0,0 @@ -/ -/ Copyright (c) 2004, 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. -/ - - .globl fs_load - .globl fs_thread - - // NOTE WELL! The _Copy functions are called directly - // from server-compiler-generated code via CallLeafNoFP, - // which means that they *must* either not use floating - // point or use it in the same manner as does the server - // compiler. - - .globl _Copy_arrayof_conjoint_bytes - .globl _Copy_conjoint_jshorts_atomic - .globl _Copy_arrayof_conjoint_jshorts - .globl _Copy_conjoint_jints_atomic - .globl _Copy_arrayof_conjoint_jints - .globl _Copy_conjoint_jlongs_atomic - .globl _Copy_arrayof_conjoint_jlongs - - .section .text,"ax" - - / Fast thread accessors, used by threadLS_solaris_amd64.cpp - .align 16 -fs_load: - movq %fs:(%rdi),%rax - ret - - .align 16 -fs_thread: - movq %fs:0x0,%rax - ret - - .globl SpinPause - .align 16 -SpinPause: - rep - nop - movq $1, %rax - ret - - - / Support for void Copy::arrayof_conjoint_bytes(void* from, - / void* to, - / size_t count) - / rdi - from - / rsi - to - / rdx - count, treated as ssize_t - / - .align 16 -_Copy_arrayof_conjoint_bytes: - movq %rdx,%r8 / byte count - shrq $3,%rdx / qword count - cmpq %rdi,%rsi - leaq -1(%rdi,%r8,1),%rax / from + bcount*1 - 1 - jbe acb_CopyRight - cmpq %rax,%rsi - jbe acb_CopyLeft -acb_CopyRight: - leaq -8(%rdi,%rdx,8),%rax / from + qcount*8 - 8 - leaq -8(%rsi,%rdx,8),%rcx / to + qcount*8 - 8 - negq %rdx - jmp 7f - .align 16 -1: movq 8(%rax,%rdx,8),%rsi - movq %rsi,8(%rcx,%rdx,8) - addq $1,%rdx - jnz 1b -2: testq $4,%r8 / check for trailing dword - jz 3f - movl 8(%rax),%esi / copy trailing dword - movl %esi,8(%rcx) - addq $4,%rax - addq $4,%rcx / original %rsi is trashed, so we - / can't use it as a base register -3: testq $2,%r8 / check for trailing word - jz 4f - movw 8(%rax),%si / copy trailing word - movw %si,8(%rcx) - addq $2,%rcx -4: testq $1,%r8 / check for trailing byte - jz 5f - movb -1(%rdi,%r8,1),%al / copy trailing byte - movb %al,8(%rcx) -5: ret - .align 16 -6: movq -24(%rax,%rdx,8),%rsi - movq %rsi,-24(%rcx,%rdx,8) - movq -16(%rax,%rdx,8),%rsi - movq %rsi,-16(%rcx,%rdx,8) - movq -8(%rax,%rdx,8),%rsi - movq %rsi,-8(%rcx,%rdx,8) - movq (%rax,%rdx,8),%rsi - movq %rsi,(%rcx,%rdx,8) -7: addq $4,%rdx - jle 6b - subq $4,%rdx - jl 1b - jmp 2b -acb_CopyLeft: - testq $1,%r8 / check for trailing byte - jz 1f - movb -1(%rdi,%r8,1),%cl / copy trailing byte - movb %cl,-1(%rsi,%r8,1) - subq $1,%r8 / adjust for possible trailing word -1: testq $2,%r8 / check for trailing word - jz 2f - movw -2(%rdi,%r8,1),%cx / copy trailing word - movw %cx,-2(%rsi,%r8,1) -2: testq $4,%r8 / check for trailing dword - jz 5f - movl (%rdi,%rdx,8),%ecx / copy trailing dword - movl %ecx,(%rsi,%rdx,8) - jmp 5f - .align 16 -3: movq -8(%rdi,%rdx,8),%rcx - movq %rcx,-8(%rsi,%rdx,8) - subq $1,%rdx - jnz 3b - ret - .align 16 -4: movq 24(%rdi,%rdx,8),%rcx - movq %rcx,24(%rsi,%rdx,8) - movq 16(%rdi,%rdx,8),%rcx - movq %rcx,16(%rsi,%rdx,8) - movq 8(%rdi,%rdx,8),%rcx - movq %rcx,8(%rsi,%rdx,8) - movq (%rdi,%rdx,8),%rcx - movq %rcx,(%rsi,%rdx,8) -5: subq $4,%rdx - jge 4b - addq $4,%rdx - jg 3b - ret - - / Support for void Copy::arrayof_conjoint_jshorts(void* from, - / void* to, - / size_t count) - / Equivalent to - / conjoint_jshorts_atomic - / - / If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we - / let the hardware handle it. The tow or four words within dwords - / or qwords that span cache line boundaries will still be loaded - / and stored atomically. - / - / rdi - from - / rsi - to - / rdx - count, treated as ssize_t - / - .align 16 -_Copy_arrayof_conjoint_jshorts: -_Copy_conjoint_jshorts_atomic: - movq %rdx,%r8 / word count - shrq $2,%rdx / qword count - cmpq %rdi,%rsi - leaq -2(%rdi,%r8,2),%rax / from + wcount*2 - 2 - jbe acs_CopyRight - cmpq %rax,%rsi - jbe acs_CopyLeft -acs_CopyRight: - leaq -8(%rdi,%rdx,8),%rax / from + qcount*8 - 8 - leaq -8(%rsi,%rdx,8),%rcx / to + qcount*8 - 8 - negq %rdx - jmp 6f -1: movq 8(%rax,%rdx,8),%rsi - movq %rsi,8(%rcx,%rdx,8) - addq $1,%rdx - jnz 1b -2: testq $2,%r8 / check for trailing dword - jz 3f - movl 8(%rax),%esi / copy trailing dword - movl %esi,8(%rcx) - addq $4,%rcx / original %rsi is trashed, so we - / can't use it as a base register -3: testq $1,%r8 / check for trailing word - jz 4f - movw -2(%rdi,%r8,2),%si / copy trailing word - movw %si,8(%rcx) -4: ret - .align 16 -5: movq -24(%rax,%rdx,8),%rsi - movq %rsi,-24(%rcx,%rdx,8) - movq -16(%rax,%rdx,8),%rsi - movq %rsi,-16(%rcx,%rdx,8) - movq -8(%rax,%rdx,8),%rsi - movq %rsi,-8(%rcx,%rdx,8) - movq (%rax,%rdx,8),%rsi - movq %rsi,(%rcx,%rdx,8) -6: addq $4,%rdx - jle 5b - subq $4,%rdx - jl 1b - jmp 2b -acs_CopyLeft: - testq $1,%r8 / check for trailing word - jz 1f - movw -2(%rdi,%r8,2),%cx / copy trailing word - movw %cx,-2(%rsi,%r8,2) -1: testq $2,%r8 / check for trailing dword - jz 4f - movl (%rdi,%rdx,8),%ecx / copy trailing dword - movl %ecx,(%rsi,%rdx,8) - jmp 4f -2: movq -8(%rdi,%rdx,8),%rcx - movq %rcx,-8(%rsi,%rdx,8) - subq $1,%rdx - jnz 2b - ret - .align 16 -3: movq 24(%rdi,%rdx,8),%rcx - movq %rcx,24(%rsi,%rdx,8) - movq 16(%rdi,%rdx,8),%rcx - movq %rcx,16(%rsi,%rdx,8) - movq 8(%rdi,%rdx,8),%rcx - movq %rcx,8(%rsi,%rdx,8) - movq (%rdi,%rdx,8),%rcx - movq %rcx,(%rsi,%rdx,8) -4: subq $4,%rdx - jge 3b - addq $4,%rdx - jg 2b - ret - - / Support for void Copy::arrayof_conjoint_jints(jint* from, - / jint* to, - / size_t count) - / Equivalent to - / conjoint_jints_atomic - / - / If 'from' and/or 'to' are aligned on 4-byte boundaries, we let - / the hardware handle it. The two dwords within qwords that span - / cache line boundaries will still be loaded and stored atomically. - / - / rdi - from - / rsi - to - / rdx - count, treated as ssize_t - / - .align 16 -_Copy_arrayof_conjoint_jints: -_Copy_conjoint_jints_atomic: - movq %rdx,%r8 / dword count - shrq %rdx / qword count - cmpq %rdi,%rsi - leaq -4(%rdi,%r8,4),%rax / from + dcount*4 - 4 - jbe aci_CopyRight - cmpq %rax,%rsi - jbe aci_CopyLeft -aci_CopyRight: - leaq -8(%rdi,%rdx,8),%rax / from + qcount*8 - 8 - leaq -8(%rsi,%rdx,8),%rcx / to + qcount*8 - 8 - negq %rdx - jmp 5f - .align 16 -1: movq 8(%rax,%rdx,8),%rsi - movq %rsi,8(%rcx,%rdx,8) - addq $1,%rdx - jnz 1b -2: testq $1,%r8 / check for trailing dword - jz 3f - movl 8(%rax),%esi / copy trailing dword - movl %esi,8(%rcx) -3: ret - .align 16 -4: movq -24(%rax,%rdx,8),%rsi - movq %rsi,-24(%rcx,%rdx,8) - movq -16(%rax,%rdx,8),%rsi - movq %rsi,-16(%rcx,%rdx,8) - movq -8(%rax,%rdx,8),%rsi - movq %rsi,-8(%rcx,%rdx,8) - movq (%rax,%rdx,8),%rsi - movq %rsi,(%rcx,%rdx,8) -5: addq $4,%rdx - jle 4b - subq $4,%rdx - jl 1b - jmp 2b -aci_CopyLeft: - testq $1,%r8 / check for trailing dword - jz 3f - movl -4(%rdi,%r8,4),%ecx / copy trailing dword - movl %ecx,-4(%rsi,%r8,4) - jmp 3f -1: movq -8(%rdi,%rdx,8),%rcx - movq %rcx,-8(%rsi,%rdx,8) - subq $1,%rdx - jnz 1b - ret - .align 16 -2: movq 24(%rdi,%rdx,8),%rcx - movq %rcx,24(%rsi,%rdx,8) - movq 16(%rdi,%rdx,8),%rcx - movq %rcx,16(%rsi,%rdx,8) - movq 8(%rdi,%rdx,8),%rcx - movq %rcx,8(%rsi,%rdx,8) - movq (%rdi,%rdx,8),%rcx - movq %rcx,(%rsi,%rdx,8) -3: subq $4,%rdx - jge 2b - addq $4,%rdx - jg 1b - ret - - / Support for void Copy::arrayof_conjoint_jlongs(jlong* from, - / jlong* to, - / size_t count) - / Equivalent to - / conjoint_jlongs_atomic - / arrayof_conjoint_oops - / conjoint_oops_atomic - / - / rdi - from - / rsi - to - / rdx - count, treated as ssize_t - / - .align 16 -_Copy_arrayof_conjoint_jlongs: -_Copy_conjoint_jlongs_atomic: - cmpq %rdi,%rsi - leaq -8(%rdi,%rdx,8),%rax / from + count*8 - 8 - jbe acl_CopyRight - cmpq %rax,%rsi - jbe acl_CopyLeft -acl_CopyRight: - leaq -8(%rsi,%rdx,8),%rcx / to + count*8 - 8 - negq %rdx - jmp 3f -1: movq 8(%rax,%rdx,8),%rsi - movq %rsi,8(%rcx,%rdx,8) - addq $1,%rdx - jnz 1b - ret - .align 16 -2: movq -24(%rax,%rdx,8),%rsi - movq %rsi,-24(%rcx,%rdx,8) - movq -16(%rax,%rdx,8),%rsi - movq %rsi,-16(%rcx,%rdx,8) - movq -8(%rax,%rdx,8),%rsi - movq %rsi,-8(%rcx,%rdx,8) - movq (%rax,%rdx,8),%rsi - movq %rsi,(%rcx,%rdx,8) -3: addq $4,%rdx - jle 2b - subq $4,%rdx - jl 1b - ret -4: movq -8(%rdi,%rdx,8),%rcx - movq %rcx,-8(%rsi,%rdx,8) - subq $1,%rdx - jnz 4b - ret - .align 16 -5: movq 24(%rdi,%rdx,8),%rcx - movq %rcx,24(%rsi,%rdx,8) - movq 16(%rdi,%rdx,8),%rcx - movq %rcx,16(%rsi,%rdx,8) - movq 8(%rdi,%rdx,8),%rcx - movq %rcx,8(%rsi,%rdx,8) - movq (%rdi,%rdx,8),%rcx - movq %rcx,(%rsi,%rdx,8) -acl_CopyLeft: - subq $4,%rdx - jge 5b - addq $4,%rdx - jg 4b - ret diff --git a/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2003, 2020, 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. - * - */ - -#include "precompiled.hpp" -#include "memory/metaspaceShared.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/thread.inline.hpp" - -frame JavaThread::pd_last_frame() { - assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); - vmassert(_anchor.last_Java_pc() != NULL, "not walkable"); - return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); -} - -// For Forte Analyzer AsyncGetCallTrace profiling support - thread is -// currently interrupted by SIGPROF -bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, - void* ucontext, bool isInJava) { - assert(Thread::current() == this, "caller must be current thread"); - return pd_get_top_frame(fr_addr, ucontext, isInJava); -} - -bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, - void* ucontext, bool isInJava) { - return pd_get_top_frame(fr_addr, ucontext, isInJava); -} - -bool JavaThread::pd_get_top_frame(frame* fr_addr, - void* ucontext, bool isInJava) { - assert(this->is_Java_thread(), "must be JavaThread"); - JavaThread* jt = (JavaThread *)this; - - // There is small window where last_Java_frame is not walkable or safe - if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { - *fr_addr = jt->pd_last_frame(); - return true; - } - - ucontext_t* uc = (ucontext_t*) ucontext; - - // We always want to use the initial frame we create from the ucontext as - // it certainly signals where we currently are. However that frame may not - // be safe for calling sender. In that case if we have a last_Java_frame - // then the forte walker will switch to that frame as the virtual sender - // for the frame we create here which is not sender safe. - - intptr_t* ret_fp; - intptr_t* ret_sp; - ExtendedPC addr = os::Solaris::fetch_frame_from_ucontext(this, uc, &ret_sp, &ret_fp); - - // Something would really have to be screwed up to get a NULL pc - - if (addr.pc() == NULL) { - assert(false, "NULL pc from signal handler!"); - return false; - } - - if (MetaspaceShared::is_in_trampoline_frame(addr.pc())) { - // In the middle of a trampoline call. Bail out for safety. - // This happens rarely so shouldn't affect profiling. - return false; - } - - // If sp and fp are nonsense just leave them out - - if (!jt->is_in_full_stack((address)ret_sp)) { - ret_sp = NULL; - ret_fp = NULL; - } else { - // sp is reasonable is fp reasonable? - if (!jt->is_in_stack_range_incl((address)ret_fp, (address)ret_sp)) { - ret_fp = NULL; - } - } - - frame ret_frame(ret_sp, ret_fp, addr.pc()); - - *fr_addr = ret_frame; - return true; - -} - -void JavaThread::cache_global_variables() { } diff --git a/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 1999, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_THREAD_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_THREAD_SOLARIS_X86_HPP - - private: - void pd_initialize() { _anchor.clear(); } - - frame pd_last_frame(); - - public: - // Mutators are highly dangerous.... - intptr_t* last_Java_fp() { return _anchor.last_Java_fp(); } - void set_last_Java_fp(intptr_t* fp) { _anchor.set_last_Java_fp(fp); } - - void set_base_of_stack_pointer(intptr_t* base_sp) {} - - static ByteSize last_Java_fp_offset() { - return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset(); - } - - intptr_t* base_of_stack_pointer() { return NULL; } - void record_base_of_stack_pointer() {} - - bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, - bool isInJava); - bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, - bool isInJava); -private: - bool pd_get_top_frame(frame* fr_addr, void* ucontext, - bool isInJava); -public: - - // These routines are only used on cpu architectures that - // have separate register stacks (Itanium). - static bool register_stack_overflow() { return false; } - static void enable_register_stack_guard() {} - static void disable_register_stack_guard() {} - -#endif // OS_CPU_SOLARIS_X86_THREAD_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2000, 2019, 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. - * - */ - -#ifndef OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP -#define OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP - -// These are the OS and CPU-specific fields, types and integer -// constants required by the Serviceability Agent. This file is -// referenced by vmStructs.cpp. - -#define VM_STRUCTS_OS_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) - -#define VM_TYPES_OS_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_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) - -#endif // OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP diff --git a/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp deleted file mode 100644 --- a/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2006, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "runtime/os.hpp" -#include "runtime/vm_version.hpp" - diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -1043,11 +1043,7 @@ const char *opType = NULL; while (_matrule->base_operand(position, globals, result, name, opType)) { if ( strcmp(opType,"ConP") == 0 ) { -#ifdef SPARC - reloc_entries += 2; // 1 for sethi + 1 for setlo -#else ++reloc_entries; -#endif } ++position; } @@ -1081,13 +1077,7 @@ // Check for any component being an immediate float or double. Form::DataType data_type = is_chain_of_constant(globals); if( data_type==idealD || data_type==idealF ) { -#ifdef SPARC - // sparc required more relocation entries for floating constants - // (expires 9/98) - reloc_entries += 6; -#else reloc_entries++; -#endif } return reloc_entries; diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -724,11 +724,7 @@ /* Do Nothing */; else if (_pipeline->_maxcycleused <= -#ifdef SPARC - 64 -#else 32 -#endif ) { fprintf(fp_cpp, "Pipeline_Use_Cycle_Mask operator&(const Pipeline_Use_Cycle_Mask &in1, const Pipeline_Use_Cycle_Mask &in2) {\n"); fprintf(fp_cpp, " return Pipeline_Use_Cycle_Mask(in1._mask & in2._mask);\n"); diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -742,11 +742,7 @@ fprintf(fp_hpp, "class Pipeline_Use_Cycle_Mask {\n"); if (_pipeline->_maxcycleused <= -#ifdef SPARC - 64 -#else 32 -#endif ) { fprintf(fp_hpp, "protected:\n"); fprintf(fp_hpp, " %s _mask;\n\n", _pipeline->_maxcycleused <= 32 ? "uint" : "uint64_t" ); diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -211,7 +211,7 @@ case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: case vmIntrinsics::_updateByteBufferCRC32: -#if defined(SPARC) || defined(S390) || defined(PPC64) || defined(AARCH64) +#if defined(S390) || defined(PPC64) || defined(AARCH64) case vmIntrinsics::_updateBytesCRC32C: case vmIntrinsics::_updateDirectByteBufferCRC32C: #endif diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -2081,23 +2081,6 @@ Value recv = has_receiver ? apop() : NULL; int vtable_index = Method::invalid_vtable_index; -#ifdef SPARC - // Currently only supported on Sparc. - // The UseInlineCaches only controls dispatch to invokevirtuals for - // loaded classes which we weren't able to statically bind. - if (!UseInlineCaches && target->is_loaded() && code == Bytecodes::_invokevirtual - && !target->can_be_statically_bound()) { - // Find a vtable index if one is available - // For arrays, callee_holder is Object. Resolving the call with - // Object would allow an illegal call to finalize() on an - // array. We use holder instead: illegal calls to finalize() won't - // be compiled as vtable calls (IC call resolution will catch the - // illegal call) and the few legal calls on array types won't be - // either. - vtable_index = target->resolve_vtable_index(calling_klass, holder); - } -#endif - // A null check is required here (when there is a receiver) for any of the following cases // - invokespecial, always need a null check. // - invokevirtual, when the target is final and loaded. Calls to final targets will become optimized diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -572,16 +572,6 @@ monitor_address(op->in_opr()->as_constant_ptr()->as_jint(), op->result_opr()); break; -#ifdef SPARC - case lir_pack64: - pack64(op->in_opr(), op->result_opr()); - break; - - case lir_unpack64: - unpack64(op->in_opr(), op->result_opr()); - break; -#endif - case lir_unwind: unwind_op(op->in_opr()); break; @@ -835,11 +825,7 @@ if (!r->is_stack()) { stringStream st; st.print("bad oop %s at %d", r->as_Register()->name(), _masm->offset()); -#ifdef SPARC - _masm->_verify_oop(r->as_Register(), os::strdup(st.as_string(), mtCompiler), __FILE__, __LINE__); -#else _masm->verify_oop(r->as_Register()); -#endif } else { _masm->verify_stack_oop(r->reg2stack() * VMRegImpl::stack_slot_size); } diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -2129,11 +2129,11 @@ #ifdef _LP64 return LIR_OprFact::double_cpu(assigned_reg, assigned_reg); #else -#if defined(SPARC) || defined(PPC32) +#if defined(PPC32) return LIR_OprFact::double_cpu(assigned_regHi, assigned_reg); #else return LIR_OprFact::double_cpu(assigned_reg, assigned_regHi); -#endif // SPARC +#endif // PPC32 #endif // LP64 } @@ -2173,12 +2173,7 @@ } #endif // X86 -#ifdef SPARC - assert(assigned_reg >= pd_first_fpu_reg && assigned_reg <= pd_last_fpu_reg, "no fpu register"); - assert(interval->assigned_regHi() >= pd_first_fpu_reg && interval->assigned_regHi() <= pd_last_fpu_reg, "no fpu register"); - assert(assigned_reg % 2 == 0 && assigned_reg + 1 == interval->assigned_regHi(), "must be sequential and even"); - LIR_Opr result = LIR_OprFact::double_fpu(interval->assigned_regHi() - pd_first_fpu_reg, assigned_reg - pd_first_fpu_reg); -#elif defined(ARM32) +#if defined(ARM32) assert(assigned_reg >= pd_first_fpu_reg && assigned_reg <= pd_last_fpu_reg, "no fpu register"); assert(interval->assigned_regHi() >= pd_first_fpu_reg && interval->assigned_regHi() <= pd_last_fpu_reg, "no fpu register"); assert(assigned_reg % 2 == 0 && assigned_reg + 1 == interval->assigned_regHi(), "must be sequential and even"); @@ -2778,9 +2773,6 @@ #ifdef AMD64 assert(false, "FPU not used on x86-64"); #endif -#ifdef SPARC - assert(opr->fpu_regnrLo() == opr->fpu_regnrHi() + 1, "assumed in calculation (only fpu_regnrHi is used)"); -#endif #ifdef ARM32 assert(opr->fpu_regnrHi() == opr->fpu_regnrLo() + 1, "assumed in calculation (only fpu_regnrLo is used)"); #endif diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -242,7 +242,7 @@ case fpu2long_stub_id: case unwind_exception_id: case counter_overflow_id: -#if defined(SPARC) || defined(PPC32) +#if defined(PPC32) case handle_exception_nofpu_id: // Unused on sparc #endif expect_oop_map = false; @@ -1133,7 +1133,7 @@ ShouldNotReachHere(); } -#if defined(SPARC) || defined(PPC32) +#if defined(PPC32) if (load_klass_or_mirror_patch_id || stub_id == Runtime1::load_appendix_patching_id) { // Update the location in the nmethod with the proper @@ -1224,13 +1224,6 @@ RelocIterator iter(nm, (address)instr_pc, (address)(instr_pc + 1)); relocInfo::change_reloc_info_for_address(&iter, (address) instr_pc, relocInfo::none, rtype); -#ifdef SPARC - // Sparc takes two relocations for an metadata so update the second one. - address instr_pc2 = instr_pc + NativeMovConstReg::add_offset; - RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1); - relocInfo::change_reloc_info_for_address(&iter2, (address) instr_pc2, - relocInfo::none, rtype); -#endif #ifdef PPC32 { address instr_pc2 = instr_pc + NativeMovConstReg::lo_offset; RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1); diff --git a/src/hotspot/share/classfile/classListParser.cpp b/src/hotspot/share/classfile/classListParser.cpp --- a/src/hotspot/share/classfile/classListParser.cpp +++ b/src/hotspot/share/classfile/classListParser.cpp @@ -280,7 +280,7 @@ // This function is used for loading classes for customized class loaders // during archive dumping. InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS) { -#if !(defined(_LP64) && (defined(LINUX)|| defined(SOLARIS) || defined(__APPLE__))) +#if !(defined(_LP64) && (defined(LINUX) || defined(__APPLE__))) // The only supported platforms are: (1) Linux/64-bit and (2) Solaris/64-bit and // (3) MacOSX/64-bit // This #if condition should be in sync with the areCustomLoadersSupportedForCDS diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -315,8 +315,7 @@ narrowOop *nl = (narrowOop*)loc; #ifndef VM_LITTLE_ENDIAN VMReg vmReg = omv.reg(); - // Don't do this on SPARC float registers as they can be individually addressed - if (!vmReg->is_stack() SPARC_ONLY(&& !vmReg->is_FloatRegister())) { + if (!vmReg->is_stack()) { // compressed oops in registers only take up 4 bytes of an // 8 byte register but they are in the wrong part of the // word so adjust loc to point at the right place. diff --git a/src/hotspot/share/compiler/tieredThresholdPolicy.cpp b/src/hotspot/share/compiler/tieredThresholdPolicy.cpp --- a/src/hotspot/share/compiler/tieredThresholdPolicy.cpp +++ b/src/hotspot/share/compiler/tieredThresholdPolicy.cpp @@ -297,7 +297,7 @@ } #endif -#if defined SPARC || defined AARCH64 +#if defined AARCH64 if (FLAG_IS_DEFAULT(InlineSmallCode)) { FLAG_SET_DEFAULT(InlineSmallCode, 2500); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp --- a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp @@ -34,13 +34,8 @@ public: // We use different types to represent the state value depending on platform as // some have issues loading parts of words. -#ifdef SPARC - typedef int32_t region_type_t; - typedef uint32_t needs_remset_update_t; -#else typedef int8_t region_type_t; typedef uint8_t needs_remset_update_t; -#endif private: needs_remset_update_t _needs_remset_update; diff --git a/src/hotspot/share/gc/shared/memset_with_concurrent_readers.hpp b/src/hotspot/share/gc/shared/memset_with_concurrent_readers.hpp --- a/src/hotspot/share/gc/shared/memset_with_concurrent_readers.hpp +++ b/src/hotspot/share/gc/shared/memset_with_concurrent_readers.hpp @@ -34,17 +34,8 @@ // understanding that there may be concurrent readers of that memory. void memset_with_concurrent_readers(void* to, int value, size_t size); -#ifdef SPARC - -// SPARC requires special handling. See SPARC-specific definition. - -#else -// All others just use memset. - inline void memset_with_concurrent_readers(void* to, int value, size_t size) { ::memset(to, value, size); } -#endif // End of target dispatch. - #endif // SHARE_GC_SHARED_MEMSET_WITH_CONCURRENT_READERS_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp @@ -37,7 +37,7 @@ } bool ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() { -#if (defined(X86) || defined(AARCH64)) && !defined(SOLARIS) +#if (defined(X86) || defined(AARCH64)) return ShenandoahCodeRootsStyle == 2 && ClassUnloading; #else diff --git a/src/hotspot/share/interpreter/abstractInterpreter.hpp b/src/hotspot/share/interpreter/abstractInterpreter.hpp --- a/src/hotspot/share/interpreter/abstractInterpreter.hpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.hpp @@ -241,7 +241,7 @@ } static int expr_offset_in_bytes(int i) { -#if !defined(ZERO) && (defined(PPC) || defined(S390) || defined(SPARC)) +#if !defined(ZERO) && (defined(PPC) || defined(S390)) return stackElementSize * i + wordSize; // both point to one word past TOS #else return stackElementSize * i; diff --git a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp --- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp @@ -3488,12 +3488,6 @@ tty->print_cr("stack_base: " INTPTR_FORMAT, (uintptr_t) this->_stack_base); tty->print_cr("stack_limit: " INTPTR_FORMAT, (uintptr_t) this->_stack_limit); tty->print_cr("monitor_base: " INTPTR_FORMAT, (uintptr_t) this->_monitor_base); -#ifdef SPARC - tty->print_cr("last_Java_pc: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_pc); - tty->print_cr("frame_bottom: " INTPTR_FORMAT, (uintptr_t) this->_frame_bottom); - tty->print_cr("&native_fresult: " INTPTR_FORMAT, (uintptr_t) &this->_native_fresult); - tty->print_cr("native_lresult: " INTPTR_FORMAT, (uintptr_t) this->_native_lresult); -#endif #if !defined(ZERO) && defined(PPC) tty->print_cr("last_Java_fp: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_fp); #endif // !ZERO diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp @@ -109,10 +109,6 @@ void generate_counter_overflow(Label& continue_entry); void generate_fixed_frame(bool native_call); -#ifdef SPARC - void save_native_result(void); - void restore_native_result(void); -#endif // SPARC #ifdef AARCH64 void generate_transcendental_entry(AbstractInterpreter::MethodKind kind, int fpargs); diff --git a/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp --- a/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp +++ b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp @@ -102,7 +102,7 @@ inline bool JfrBigEndian::platform_supports_unaligned_reads(void) { #if defined(IA32) || defined(AMD64) || defined(PPC) || defined(S390) return true; -#elif defined(SPARC) || defined(ARM) || defined(AARCH64) +#elif defined(ARM) || defined(AARCH64) return false; #else #warning "Unconfigured platform" diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -792,61 +792,6 @@ #endif - -#ifdef SPARC - -#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) \ - volatile_nonstatic_field(JavaFrameAnchor, _flags, int) - -#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ - declare_constant(VM_Version::ISA_V9) \ - declare_constant(VM_Version::ISA_POPC) \ - declare_constant(VM_Version::ISA_VIS1) \ - declare_constant(VM_Version::ISA_VIS2) \ - declare_constant(VM_Version::ISA_BLK_INIT) \ - declare_constant(VM_Version::ISA_FMAF) \ - declare_constant(VM_Version::ISA_VIS3) \ - declare_constant(VM_Version::ISA_HPC) \ - declare_constant(VM_Version::ISA_IMA) \ - declare_constant(VM_Version::ISA_AES) \ - declare_constant(VM_Version::ISA_DES) \ - declare_constant(VM_Version::ISA_KASUMI) \ - declare_constant(VM_Version::ISA_CAMELLIA) \ - declare_constant(VM_Version::ISA_MD5) \ - declare_constant(VM_Version::ISA_SHA1) \ - declare_constant(VM_Version::ISA_SHA256) \ - declare_constant(VM_Version::ISA_SHA512) \ - declare_constant(VM_Version::ISA_MPMUL) \ - declare_constant(VM_Version::ISA_MONT) \ - declare_constant(VM_Version::ISA_PAUSE) \ - declare_constant(VM_Version::ISA_CBCOND) \ - declare_constant(VM_Version::ISA_CRC32C) \ - declare_constant(VM_Version::ISA_VIS3B) \ - declare_constant(VM_Version::ISA_ADI) \ - declare_constant(VM_Version::ISA_SPARC5) \ - declare_constant(VM_Version::ISA_MWAIT) \ - declare_constant(VM_Version::ISA_XMPMUL) \ - declare_constant(VM_Version::ISA_XMONT) \ - declare_constant(VM_Version::ISA_PAUSE_NSEC) \ - declare_constant(VM_Version::ISA_VAMASK) \ - declare_constant(VM_Version::ISA_SPARC6) \ - declare_constant(VM_Version::ISA_DICTUNP) \ - declare_constant(VM_Version::ISA_FPCMPSHL) \ - declare_constant(VM_Version::ISA_RLE) \ - declare_constant(VM_Version::ISA_SHA3) \ - declare_constant(VM_Version::ISA_VIS3C) \ - declare_constant(VM_Version::ISA_SPARC5B) \ - declare_constant(VM_Version::ISA_MME) \ - declare_constant(VM_Version::CPU_FAST_IDIV) \ - declare_constant(VM_Version::CPU_FAST_RDPC) \ - declare_constant(VM_Version::CPU_FAST_BIS) \ - declare_constant(VM_Version::CPU_FAST_LD) \ - declare_constant(VM_Version::CPU_FAST_CMOVE) \ - declare_constant(VM_Version::CPU_FAST_IND_BR) \ - declare_constant(VM_Version::CPU_BLK_ZEROING) -#endif - - /* * Dummy defines for architectures that don't use these. */ diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -174,11 +174,6 @@ void* Amalloc_D(size_t x, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) { assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" ); debug_only(if (UseMallocOnly) return malloc(x);) -#if defined(SPARC) && !defined(_LP64) -#define DALIGN_M1 7 - size_t delta = (((size_t)_hwm + DALIGN_M1) & ~DALIGN_M1) - (size_t)_hwm; - x += delta; -#endif if (!check_for_overflow(x, "Arena::Amalloc_D", alloc_failmode)) return NULL; if (_hwm + x > _max) { @@ -186,9 +181,6 @@ } else { char *old = _hwm; _hwm += x; -#if defined(SPARC) && !defined(_LP64) - old += delta; // align to 8-bytes -#endif return old; } } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -361,9 +361,6 @@ product(bool, BranchOnRegister, false, \ "Use Sparc V9 branch-on-register opcodes") \ \ - develop(bool, SparcV9RegsHiBitsZero, true, \ - "Assume Sparc V9 I&L registers on V8+ systems are zero-extended") \ - \ product(bool, UseRDPCForConstantTableBase, false, \ "Use Sparc RDPC instruction for the constant table base.") \ \ diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -869,11 +869,7 @@ // SPARCV9 2 2 2 2 2 48 (24) 52 (26) // AMD64 1 1 1 1 1 14 15 // ----------------------------------------------------- -#if defined(SPARC) - lrg.set_reg_pressure(2); // use for v9 as well -#else lrg.set_reg_pressure(1); // normally one value per register -#endif if( n_type->isa_oop_ptr() ) { lrg._is_oop = 1; } @@ -882,7 +878,7 @@ case Op_RegD: lrg.set_num_regs(2); // Define platform specific register pressure -#if defined(SPARC) || defined(ARM32) +#if defined(ARM32) lrg.set_reg_pressure(2); #elif defined(IA32) if( ireg == Op_RegL ) { @@ -909,11 +905,7 @@ case Op_RegFlags: case 0: // not an ideal register lrg.set_num_regs(1); -#ifdef SPARC - lrg.set_reg_pressure(2); -#else lrg.set_reg_pressure(1); -#endif break; case Op_VecS: assert(Matcher::vector_size_supported(T_BYTE,4), "sanity"); @@ -1486,10 +1478,6 @@ // Check if a color is available and if so pick the color OptoReg::Name reg = choose_color( *lrg, chunk ); -#ifdef SPARC - debug_only(lrg->compute_set_mask_size()); - assert(lrg->num_regs() < 2 || lrg->is_bound() || is_even(reg-1), "allocate all doubles aligned"); -#endif //--------------- // If we fail to color and the AllStack flag is set, trigger diff --git a/src/hotspot/share/opto/generateOptoStub.cpp b/src/hotspot/share/opto/generateOptoStub.cpp --- a/src/hotspot/share/opto/generateOptoStub.cpp +++ b/src/hotspot/share/opto/generateOptoStub.cpp @@ -92,13 +92,6 @@ thread, in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::last_Java_pc_offset())); -#if defined(SPARC) - Node* adr_flags = basic_plus_adr(top(), - thread, - in_bytes(JavaThread::frame_anchor_offset()) + - in_bytes(JavaFrameAnchor::flags_offset())); -#endif /* defined(SPARC) */ - // Drop in the last_Java_sp. last_Java_fp is not touched. // Always do this after the other "last_Java_frame" fields are set since @@ -231,9 +224,6 @@ store_to_memory(NULL, adr_sp, null(), T_ADDRESS, NoAlias, MemNode::unordered); // Clear last_Java_pc and (optionally)_flags store_to_memory(NULL, adr_last_Java_pc, null(), T_ADDRESS, NoAlias, MemNode::unordered); -#if defined(SPARC) - store_to_memory(NULL, adr_flags, intcon(0), T_INT, NoAlias, MemNode::unordered); -#endif /* defined(SPARC) */ #if (defined(IA64) && !defined(AIX)) Node* adr_last_Java_fp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_fp_offset())); store_to_memory(NULL, adr_last_Java_fp, null(), T_ADDRESS, NoAlias, MemNode::unordered); diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -804,14 +804,6 @@ array->append(new_loc_value( C->regalloc(), regnum, Location::lng )); } #else //_LP64 -#ifdef SPARC - if (t->base() == Type::Long && OptoReg::is_reg(regnum)) { - // For SPARC we have to swap high and low words for - // long values stored in a single-register (g0-g7). - array->append(new_loc_value( C->regalloc(), regnum , Location::normal )); - array->append(new_loc_value( C->regalloc(), OptoReg::add(regnum,1), Location::normal )); - } else -#endif //SPARC if( t->base() == Type::DoubleBot || t->base() == Type::DoubleCon || t->base() == Type::Long ) { // Repack the double/long as two jints. // The convention the interpreter uses is that the second local diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -61,13 +61,7 @@ { Bad, T_ILLEGAL, "tuple:", false, Node::NotAMachineReg, relocInfo::none }, // Tuple { Bad, T_ARRAY, "array:", false, Node::NotAMachineReg, relocInfo::none }, // Array -#ifdef SPARC - { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS - { Bad, T_ILLEGAL, "vectord:", false, Op_RegD, relocInfo::none }, // VectorD - { Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX - { Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY - { Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ -#elif defined(PPC64) +#if defined(PPC64) { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS { Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD { Bad, T_ILLEGAL, "vectorx:", false, Op_VecX, relocInfo::none }, // VectorX diff --git a/src/hotspot/share/precompiled/precompiled.hpp b/src/hotspot/share/precompiled/precompiled.hpp --- a/src/hotspot/share/precompiled/precompiled.hpp +++ b/src/hotspot/share/precompiled/precompiled.hpp @@ -22,8 +22,8 @@ * */ -// Precompiled headers are turned off for Solaris Studio, -// or if the user passes --disable-precompiled-headers to configure. +// Precompiled headers are turned off if the user passes +// --disable-precompiled-headers to configure. #ifndef DONT_USE_PRECOMPILED_HEADER diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -175,7 +175,6 @@ #define OS LINUX_ONLY("linux") \ WINDOWS_ONLY("windows") \ - SOLARIS_ONLY("solaris") \ AIX_ONLY("aix") \ BSD_ONLY("bsd") @@ -193,8 +192,7 @@ AMD64_ONLY("amd64") \ IA32_ONLY("x86") \ IA64_ONLY("ia64") \ - S390_ONLY("s390") \ - SPARC_ONLY("sparc") + S390_ONLY("s390") #endif // !ZERO #endif // !CPU diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1082,23 +1082,9 @@ case 4: *((jint *) check_alignment_get_addr(obj, index, 4)) = (jint) *((jint *) &val); break; - case 8: { -#ifdef _LP64 - jlong res = (jlong) *((jlong *) &val); -#else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong v = (jlong) *((jlong *) &val); - jlong res = 0; - res |= ((v & (jlong) 0xffffffff) << 32); - res |= ((v >> 32) & (jlong) 0xffffffff); -#else - jlong res = (jlong) *((jlong *) &val); -#endif // SPARC -#endif - *((jlong *) check_alignment_get_addr(obj, index, 8)) = res; + case 8: + *((jlong *) check_alignment_get_addr(obj, index, 8)) = (jlong) *((jlong *) &val); break; - } default: ShouldNotReachHere(); } @@ -1121,12 +1107,7 @@ #ifdef _LP64 jlong res = (jlong)low->get_int(); #else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); -#else jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); -#endif //SPARC #endif obj->long_at_put(index, res); break; @@ -1155,12 +1136,7 @@ #ifdef _LP64 jlong res = (jlong)low->get_int(); #else - #ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); - #else jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); - #endif //SPARC #endif obj->int_at_put(index, (jint)*((jint*)&res)); obj->int_at_put(++index, (jint)*(((jint*)&res) + 1)); @@ -1305,12 +1281,7 @@ #ifdef _LP64 jlong res = (jlong)low->get_int(); #else -#ifdef SPARC - // For SPARC we have to swap high and low words. - jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int()); -#else jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int()); -#endif //SPARC #endif obj->long_field_put(offset, res); break; diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -132,9 +132,7 @@ JVMFlag::Error AllocatePrefetchInstrConstraintFunc(intx value, bool verbose) { intx max_value = max_intx; -#if defined(SPARC) - max_value = 1; -#elif defined(X86) +#if defined(X86) max_value = 3; #endif if (value < 0 || value > max_value) { @@ -236,31 +234,10 @@ } JVMFlag::Error CompilerThreadPriorityConstraintFunc(intx value, bool verbose) { -#ifdef SOLARIS - if ((value < MinimumPriority || value > MaximumPriority) && - (value != -1) && (value != -FXCriticalPriority)) { - JVMFlag::printError(verbose, - "CompileThreadPriority (" INTX_FORMAT ") must be " - "between %d and %d inclusively or -1 (means no change) " - "or %d (special value for critical thread class/priority)\n", - value, MinimumPriority, MaximumPriority, -FXCriticalPriority); - return JVMFlag::VIOLATES_CONSTRAINT; - } -#endif - return JVMFlag::SUCCESS; } JVMFlag::Error CodeEntryAlignmentConstraintFunc(intx value, bool verbose) { -#ifdef SPARC - if (CodeEntryAlignment % relocInfo::addr_unit() != 0) { - JVMFlag::printError(verbose, - "CodeEntryAlignment (" INTX_FORMAT ") must be " - "multiple of NOP size\n", CodeEntryAlignment); - return JVMFlag::VIOLATES_CONSTRAINT; - } -#endif - if (!is_power_of_2(value)) { JVMFlag::printError(verbose, "CodeEntryAlignment (" INTX_FORMAT ") must be " @@ -288,7 +265,7 @@ return JVMFlag::VIOLATES_CONSTRAINT; } - // Relevant on ppc, s390, sparc. Will be optimized where + // Relevant on ppc, s390. Will be optimized where // addr_unit() == 1. if (OptoLoopAlignment % relocInfo::addr_unit() != 0) { JVMFlag::printError(verbose, @@ -355,15 +332,6 @@ return JVMFlag::VIOLATES_CONSTRAINT; } -#ifdef SPARC - if (InteriorEntryAlignment % relocInfo::addr_unit() != 0) { - JVMFlag::printError(verbose, - "InteriorEntryAlignment (" INTX_FORMAT ") must be " - "multiple of NOP size\n"); - return JVMFlag::VIOLATES_CONSTRAINT; - } -#endif - if (!is_power_of_2(value)) { JVMFlag::printError(verbose, "InteriorEntryAlignment (" INTX_FORMAT ") must be " @@ -372,7 +340,7 @@ } int minimum_alignment = 16; -#if defined(SPARC) || (defined(X86) && !defined(AMD64)) +#if defined(X86) && !defined(AMD64) minimum_alignment = 4; #elif defined(S390) minimum_alignment = 2; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -409,7 +409,7 @@ "Trace external suspend wait failures") \ \ product(bool, MaxFDLimit, true, \ - "Bump the number of file descriptors to maximum in Solaris") \ + "Bump the number of file descriptors to maximum (Unix only)") \ \ diagnostic(bool, LogEvents, true, \ "Enable the various ring buffer event logs") \ @@ -679,10 +679,6 @@ product_pd(bool, DontYieldALot, \ "Throw away obvious excess yield calls") \ \ - develop(bool, UseDetachedThreads, true, \ - "Use detached threads that are recycled upon termination " \ - "(for Solaris only)") \ - \ experimental(bool, DisablePrimordialThreadGuardPages, false, \ "Disable the use of stack guard pages if the JVM is loaded " \ "on the primordial process thread") \ @@ -704,10 +700,6 @@ "When true prevents OS-level spurious, or premature, wakeups " \ "from Object.wait (Ignored for Windows)") \ \ - develop(bool, UsePthreads, false, \ - "Use pthread-based instead of libthread-based synchronization " \ - "(SPARC only)") \ - \ product(bool, ReduceSignalUsage, false, \ "Reduce the use of OS signals in Java and/or the VM") \ \ @@ -723,11 +715,11 @@ \ product(bool, AllowUserSignalHandlers, false, \ "Do not complain if the application installs signal handlers " \ - "(Solaris & Linux only)") \ + "(Unix only)") \ \ product(bool, UseSignalChaining, true, \ "Use signal-chaining to invoke signal handlers installed " \ - "by the application (Solaris & Linux only)") \ + "by the application (Unix only)") \ \ product(bool, RestoreMXCSROnJNICalls, false, \ "Restore MXCSR when returning from JNI calls") \ @@ -1830,10 +1822,8 @@ product(intx, ThreadPriorityPolicy, 0, \ "0 : Normal. "\ " VM chooses priorities that are appropriate for normal "\ - " applications. On Solaris NORM_PRIORITY and above are mapped "\ - " to normal native priority. Java priorities below " \ - " NORM_PRIORITY map to lower native priority values. On "\ - " Windows applications are allowed to use higher native "\ + " applications. "\ + " On Windows applications are allowed to use higher native "\ " priorities. However, with ThreadPriorityPolicy=0, VM will "\ " not use the highest possible native priority, "\ " THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with "\ @@ -2397,7 +2387,7 @@ range(0, 2) \ \ experimental(size_t, ArrayAllocatorMallocLimit, \ - SOLARIS_ONLY(64*K) NOT_SOLARIS((size_t)-1), \ + (size_t)-1, \ "Allocation less than this value will be allocated " \ "using malloc. Larger allocations will use mmap.") \ \ diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -153,12 +153,6 @@ stubRoutines_init2(); // note: StubRoutines need 2-phase init MethodHandles::generate_adapters(); -#if INCLUDE_NMT - // Solaris stack is walkable only after stubRoutines are set up. - // On Other platforms, the stack is always walkable. - NMT_stack_walkable = true; -#endif // INCLUDE_NMT - // All the flags that get adjusted by VM_Version_init and os::init_2 // have been set so dump the flags now. if (PrintFlagsFinal || PrintFlagsRanges) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -444,7 +444,7 @@ static void free_thread(OSThread* osthread); - // thread id on Linux/64bit is 64bit, on Windows and Solaris, it's 32bit + // thread id on Linux/64bit is 64bit, on Windows it's 32bit static intx current_thread_id(); static int current_process_id(); @@ -771,10 +771,8 @@ // JVMTI & JVM monitoring and management support // The thread_cpu_time() and current_thread_cpu_time() are only // supported if is_thread_cpu_time_supported() returns true. - // They are not supported on Solaris T1. // Thread CPU Time - return the fast estimate on a platform - // On Solaris - call gethrvtime (fast) - user time only // On Linux - fast clock_gettime where available - user+sys // - otherwise: very slow /proc fs - user+sys // On Windows - GetThreadTimes - user+sys diff --git a/src/hotspot/share/runtime/semaphore.hpp b/src/hotspot/share/runtime/semaphore.hpp --- a/src/hotspot/share/runtime/semaphore.hpp +++ b/src/hotspot/share/runtime/semaphore.hpp @@ -28,7 +28,7 @@ #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" -#if defined(LINUX) || defined(SOLARIS) || defined(AIX) +#if defined(LINUX) || defined(AIX) # include "semaphore_posix.hpp" #elif defined(BSD) # include "semaphore_bsd.hpp" diff --git a/src/hotspot/share/runtime/stackValue.cpp b/src/hotspot/share/runtime/stackValue.cpp --- a/src/hotspot/share/runtime/stackValue.cpp +++ b/src/hotspot/share/runtime/stackValue.cpp @@ -41,12 +41,6 @@ // Stack or register value Location loc = ((LocationValue *)sv)->location(); -#ifdef SPARC - // %%%%% Callee-save floats will NOT be working on a Sparc until we - // handle the case of a 2 floats in a single double register. - assert( !(loc.is_register() && loc.type() == Location::float_in_dbl), "Sparc does not handle callee-save floats yet" ); -#endif // SPARC - // First find address of value address value_addr = loc.is_register() diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -351,12 +351,6 @@ set_stack_base(os::current_stack_base()); set_stack_size(os::current_stack_size()); -#ifdef SOLARIS - if (os::is_primordial_thread()) { - os::Solaris::correct_stack_boundaries_for_primordial_thread(this); - } -#endif - // Set stack limits after thread is initialized. if (is_Java_thread()) { ((JavaThread*) this)->set_stack_overflow_limit(); diff --git a/src/hotspot/share/services/dtraceAttacher.cpp b/src/hotspot/share/services/dtraceAttacher.cpp deleted file mode 100644 --- a/src/hotspot/share/services/dtraceAttacher.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2006, 2019, 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. - * - */ - -#include "precompiled.hpp" -#include "code/codeCache.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/vmThread.hpp" -#include "runtime/vmOperations.hpp" -#include "services/dtraceAttacher.hpp" - -#ifdef SOLARIS - -static void set_bool_flag(const char* name, bool value) { - JVMFlag* flag = JVMFlag::find_flag(name); - JVMFlag::boolAtPut(flag, &value, JVMFlag::ATTACH_ON_DEMAND); -} - -// Enable only the "fine grained" flags. Do *not* touch -// the overall "ExtendedDTraceProbes" flag. -void DTrace::enable_dprobes(int probes) { - bool changed = false; - if (!DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) { - set_bool_flag("DTraceAllocProbes", true); - changed = true; - } - if (!DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) { - set_bool_flag("DTraceMethodProbes", true); - changed = true; - } - if (!DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) { - set_bool_flag("DTraceMonitorProbes", true); - changed = true; - } - - if (changed) { - // one or more flags changed, need to deoptimize - CodeCache::mark_all_nmethods_for_deoptimization(); - Deoptimization::deoptimize_all_marked(); - } -} - -// Disable only the "fine grained" flags. Do *not* touch -// the overall "ExtendedDTraceProbes" flag. -void DTrace::disable_dprobes(int probes) { - bool changed = false; - if (DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) { - set_bool_flag("DTraceAllocProbes", false); - changed = true; - } - if (DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) { - set_bool_flag("DTraceMethodProbes", false); - changed = true; - } - if (DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) { - set_bool_flag("DTraceMonitorProbes", false); - changed = true; - } - if (changed) { - // one or more flags changed, need to deoptimize - CodeCache::mark_all_nmethods_for_deoptimization(); - Deoptimization::deoptimize_all_marked(); - } -} - -// Do clean-up on "all door clients detached" event. -void DTrace::detach_all_clients() { - /* - * We restore the state of the fine grained flags - * to be consistent with overall ExtendedDTraceProbes. - * This way, we will honour command line setting or the - * last explicit modification of ExtendedDTraceProbes by - * a call to set_extended_dprobes. - */ - if (ExtendedDTraceProbes) { - enable_dprobes(DTRACE_ALL_PROBES); - } else { - disable_dprobes(DTRACE_ALL_PROBES); - } -} - -void DTrace::set_extended_dprobes(bool flag) { - // explicit setting of ExtendedDTraceProbes flag - set_bool_flag("ExtendedDTraceProbes", flag); - - // make sure that the fine grained flags reflect the change. - if (flag) { - enable_dprobes(DTRACE_ALL_PROBES); - } else { - /* - * FIXME: Revisit this: currently all-client-detach detection - * does not work and hence disabled. The following scheme does - * not work. So, we have to disable fine-grained flags here. - * - * disable_dprobes call has to be delayed till next "detach all "event. - * This is to be done so that concurrent DTrace clients that may - * have enabled one or more fine grained dprobes and may be running - * still. On "detach all" clients event, we would sync ExtendedDTraceProbes - * with fine grained flags which would take care of disabling fine grained flags. - */ - disable_dprobes(DTRACE_ALL_PROBES); - } -} - -void DTrace::set_monitor_dprobes(bool flag) { - // explicit setting of DTraceMonitorProbes flag - set_bool_flag("DTraceMonitorProbes", flag); -} - -#endif /* SOLARIS */ diff --git a/src/hotspot/share/services/memTracker.cpp b/src/hotspot/share/services/memTracker.cpp --- a/src/hotspot/share/services/memTracker.cpp +++ b/src/hotspot/share/services/memTracker.cpp @@ -41,12 +41,6 @@ #include #endif -#ifdef SOLARIS - volatile bool NMT_stack_walkable = false; -#else - volatile bool NMT_stack_walkable = true; -#endif - volatile NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown; NMT_TrackingLevel MemTracker::_cmdline_tracking_level = NMT_unknown; diff --git a/src/hotspot/share/services/memTracker.hpp b/src/hotspot/share/services/memTracker.hpp --- a/src/hotspot/share/services/memTracker.hpp +++ b/src/hotspot/share/services/memTracker.hpp @@ -85,11 +85,9 @@ #include "services/threadStackTracker.hpp" #include "services/virtualMemoryTracker.hpp" -extern volatile bool NMT_stack_walkable; - -#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \ +#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail) ? \ NativeCallStack(0, true) : NativeCallStack::empty_stack()) -#define CALLER_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \ +#define CALLER_PC ((MemTracker::tracking_level() == NMT_detail) ? \ NativeCallStack(1, true) : NativeCallStack::empty_stack()) class MemBaseline; diff --git a/src/hotspot/share/utilities/compilerWarnings_solstudio.hpp b/src/hotspot/share/utilities/compilerWarnings_solstudio.hpp deleted file mode 100644 --- a/src/hotspot/share/utilities/compilerWarnings_solstudio.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2019, 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. - * - */ - -#ifndef SHARE_UTILITIES_COMPILERWARNINGS_SOLSTUDIO_HPP -#define SHARE_UTILITIES_COMPILERWARNINGS_SOLSTUDIO_HPP - -// Nothing here yet. - -#endif // SHARE_UTILITIES_COMPILERWARNINGS_SOLSTUDIO_HPP diff --git a/src/hotspot/share/utilities/count_trailing_zeros.hpp b/src/hotspot/share/utilities/count_trailing_zeros.hpp --- a/src/hotspot/share/utilities/count_trailing_zeros.hpp +++ b/src/hotspot/share/utilities/count_trailing_zeros.hpp @@ -87,17 +87,6 @@ } /***************************************************************************** - * Oracle Studio - *****************************************************************************/ -#elif defined(TARGET_COMPILER_solstudio) - -// No compiler built-in / intrinsic, so use inline assembler. - -#include "utilities/macros.hpp" - -#include OS_CPU_HEADER(count_trailing_zeros) - -/***************************************************************************** * Unknown toolchain *****************************************************************************/ #else diff --git a/src/hotspot/share/utilities/debug.cpp b/src/hotspot/share/utilities/debug.cpp --- a/src/hotspot/share/utilities/debug.cpp +++ b/src/hotspot/share/utilities/debug.cpp @@ -640,12 +640,11 @@ tty->print_cr(" findm(intptr_t pc) - finds Method*"); tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it"); tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g."); - tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or"); + tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 or"); tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or"); tty->print_cr(" pns($sp, $fp, $pc) on Linux/AArch64 or"); tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); tty->print_cr(" pns($sp, $s8, $pc) on Linux/mips or"); - tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC"); tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); tty->print_cr(" - in dbx do 'frame 1' before calling pns()"); diff --git a/src/hotspot/share/utilities/dtrace.hpp b/src/hotspot/share/utilities/dtrace.hpp --- a/src/hotspot/share/utilities/dtrace.hpp +++ b/src/hotspot/share/utilities/dtrace.hpp @@ -33,18 +33,14 @@ #define DTRACE_ONLY(x) x #define NOT_DTRACE(x) -#if defined(SOLARIS) -// Work around dtrace tail call bug 6672627 until it is fixed in solaris 10. -#define HS_DTRACE_WORKAROUND_TAIL_CALL_BUG() \ - do { volatile size_t dtrace_workaround_tail_call_bug = 1; } while (0) -#elif defined(LINUX) +#if defined(LINUX) #define HS_DTRACE_WORKAROUND_TAIL_CALL_BUG() #elif defined(__APPLE__) #define HS_DTRACE_WORKAROUND_TAIL_CALL_BUG() #include #else #error "dtrace enabled for unknown os" -#endif /* defined(SOLARIS) */ +#endif /* defined(LINUX) */ #include "dtracefiles/hotspot.h" #include "dtracefiles/hotspot_jni.h" diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -791,12 +791,6 @@ #define STACK_BIAS 0 -// V9 Sparc CPU's running in 64 Bit mode use a stack bias of 7ff -// in order to extend the reach of the stack pointer. -#if defined(SPARC) && defined(_LP64) -#undef STACK_BIAS -#define STACK_BIAS 0x7ff -#endif // TosState describes the top-of-stack state before and after the execution of diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp --- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -39,35 +39,15 @@ #include #include -#ifdef SOLARIS -#include -#endif // SOLARIS - #include #include #include #include #include -#ifdef SOLARIS -#include -#endif // SOLARIS - #include #include -#ifdef SOLARIS -#include -#include -#include -#include -#include -#endif // SOLARIS - -# ifdef SOLARIS_MUTATOR_LIBTHREAD -# include -# endif - #if defined(LINUX) || defined(_ALLBSD_SOURCE) #include #include @@ -81,34 +61,6 @@ #include #endif // LINUX || _ALLBSD_SOURCE -// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures -// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in -// system header files. On 32-bit architectures, there is no problem. -// On 64-bit architectures, defining NULL as a 32-bit constant can cause -// problems with varargs functions: C++ integral promotion rules say for -// varargs, we pass the argument 0 as an int. So, if NULL was passed to a -// varargs function it will remain 32-bits. Depending on the calling -// convention of the machine, if the argument is passed on the stack then -// only 32-bits of the "NULL" pointer may be initialized to zero. The -// other 32-bits will be garbage. If the varargs function is expecting a -// pointer when it extracts the argument, then we have a problem. -// -// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0. -// -// Note: this fix doesn't work well on Linux because NULL will be overwritten -// whenever a system header file is included. Linux handles NULL correctly -// through a special type '__null'. -#ifdef SOLARIS - #ifdef _LP64 - #undef NULL - #define NULL 0L - #else - #ifndef NULL - #define NULL 0 - #endif - #endif -#endif - // NULL vs NULL_WORD: // On Linux NULL is defined as a special type '__null'. Assigning __null to // integer variable will cause gcc warning. Use NULL_WORD in places where a @@ -156,52 +108,8 @@ typedef uint32_t juint; typedef uint64_t julong; - -#ifdef SOLARIS -// ANSI C++ fixes -// NOTE:In the ANSI committee's continuing attempt to make each version -// of C++ incompatible with the previous version, you can no longer cast -// pointers to functions without specifying linkage unless you want to get -// warnings. -// -// This also means that pointers to functions can no longer be "hidden" -// in opaque types like void * because at the invokation point warnings -// will be generated. While this makes perfect sense from a type safety -// point of view it causes a lot of warnings on old code using C header -// files. Here are some typedefs to make the job of silencing warnings -// a bit easier. -// -// The final kick in the teeth is that you can only have extern "C" linkage -// specified at file scope. So these typedefs are here rather than in the -// .hpp for the class (os:Solaris usually) that needs them. - -extern "C" { - typedef int (*int_fnP_thread_t_iP_uP_stack_tP_gregset_t)(thread_t, int*, unsigned *, stack_t*, gregset_t); - typedef int (*int_fnP_thread_t_i_gregset_t)(thread_t, int, gregset_t); - typedef int (*int_fnP_thread_t_i)(thread_t, int); - typedef int (*int_fnP_thread_t)(thread_t); - - typedef int (*int_fnP_cond_tP_mutex_tP_timestruc_tP)(cond_t *cv, mutex_t *mx, timestruc_t *abst); - typedef int (*int_fnP_cond_tP_mutex_tP)(cond_t *cv, mutex_t *mx); - - // typedef for missing API in libc - typedef int (*int_fnP_mutex_tP_i_vP)(mutex_t *, int, void *); - typedef int (*int_fnP_mutex_tP)(mutex_t *); - typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg); - typedef int (*int_fnP_cond_tP)(cond_t *cv); -}; -#endif // SOLARIS - // checking for nanness -#ifdef SOLARIS -#ifdef SPARC -inline int g_isnan(float f) { return isnanf(f); } -#else -// isnanf() broken on Intel Solaris use isnand() -inline int g_isnan(float f) { return isnand(f); } -#endif -inline int g_isnan(double f) { return isnand(f); } -#elif defined(__APPLE__) +#if defined(__APPLE__) inline int g_isnan(double f) { return isnan(f); } #elif defined(LINUX) || defined(_ALLBSD_SOURCE) inline int g_isnan(float f) { return isnanf(f); } diff --git a/src/hotspot/share/utilities/globalDefinitions_solstudio.hpp b/src/hotspot/share/utilities/globalDefinitions_solstudio.hpp deleted file mode 100644 --- a/src/hotspot/share/utilities/globalDefinitions_solstudio.hpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 1997, 2019, 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. - * - */ - -#ifndef SHARE_UTILITIES_GLOBALDEFINITIONS_SOLSTUDIO_HPP -#define SHARE_UTILITIES_GLOBALDEFINITIONS_SOLSTUDIO_HPP - -#include "jni.h" - -// This file holds compiler-dependent includes, -// globally used constants & types, class (forward) -// declarations and a few frequently used utility functions. - - -# include -# include -# include // for bsd'isms -# include -# include // for offsetof -# include -# include -# include -# include -#ifdef SOLARIS -# include -#endif -# include -# include -# include -# include -# include -#ifdef SOLARIS -# include -#endif -# include -# include -#ifdef SOLARIS -# include -# include -# include -# include -# include -#endif -# ifdef SOLARIS_MUTATOR_LIBTHREAD -# include -# endif - -#include - -// Solaris 8 doesn't provide definitions of these -#ifdef SOLARIS -#ifndef PRIdPTR -#if defined(_LP64) -#define PRIdPTR "ld" -#define PRIuPTR "lu" -#define PRIxPTR "lx" -#else -#define PRIdPTR "d" -#define PRIuPTR "u" -#define PRIxPTR "x" -#endif -#endif -#endif - -#ifdef LINUX -# include -# include -# include -#endif - - -// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures -// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in -// system header files. On 32-bit architectures, there is no problem. -// On 64-bit architectures, defining NULL as a 32-bit constant can cause -// problems with varargs functions: C++ integral promotion rules say for -// varargs, we pass the argument 0 as an int. So, if NULL was passed to a -// varargs function it will remain 32-bits. Depending on the calling -// convention of the machine, if the argument is passed on the stack then -// only 32-bits of the "NULL" pointer may be initialized to zero. The -// other 32-bits will be garbage. If the varargs function is expecting a -// pointer when it extracts the argument, then we have a problem. -// -// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0. -// -// Note: this fix doesn't work well on Linux because NULL will be overwritten -// whenever a system header file is included. Linux handles NULL correctly -// through a special type '__null'. -#ifdef SOLARIS -#ifdef _LP64 -#undef NULL -#define NULL 0L -#else -#ifndef NULL -#define NULL 0 -#endif -#endif -#endif - -// NULL vs NULL_WORD: -// On Linux NULL is defined as a special type '__null'. Assigning __null to -// integer variable will cause gcc warning. Use NULL_WORD in places where a -// pointer is stored as integer value. On some platforms, sizeof(intptr_t) > -// sizeof(void*), so here we want something which is integer type, but has the -// same size as a pointer. -#ifdef LINUX - #ifdef _LP64 - #define NULL_WORD 0L - #else - // Cast 0 to intptr_t rather than int32_t since they are not the same type - // on some platforms. - #define NULL_WORD ((intptr_t)0) - #endif -#else - #define NULL_WORD NULL -#endif - -#ifndef LINUX -// Compiler-specific primitive types -typedef unsigned short uint16_t; -#ifndef _UINT32_T -#define _UINT32_T -typedef unsigned int uint32_t; -#endif -#if !defined(_SYS_INT_TYPES_H) -#ifndef _UINT64_T -#define _UINT64_T -typedef unsigned long long uint64_t; -#endif -// %%%% how to access definition of intptr_t portably in 5.5 onward? -typedef int intptr_t; -typedef unsigned int uintptr_t; -// If this gets an error, figure out a symbol XXX that implies the -// prior definition of intptr_t, and add "&& !defined(XXX)" above. -#endif -#endif - -// On solaris 8, UINTPTR_MAX is defined as empty. -// Everywhere else it's an actual value. -#if UINTPTR_MAX - 1 == -1 -#undef UINTPTR_MAX -#ifdef _LP64 -#define UINTPTR_MAX UINT64_MAX -#else -#define UINTPTR_MAX UINT32_MAX -#endif /* ifdef _LP64 */ -#endif - -// Additional Java basic types - -typedef unsigned char jubyte; -typedef unsigned short jushort; -typedef unsigned int juint; -typedef unsigned long long julong; - - -#ifdef SOLARIS -// ANSI C++ fixes -// NOTE:In the ANSI committee's continuing attempt to make each version -// of C++ incompatible with the previous version, you can no longer cast -// pointers to functions without specifying linkage unless you want to get -// warnings. -// -// This also means that pointers to functions can no longer be "hidden" -// in opaque types like void * because at the invokation point warnings -// will be generated. While this makes perfect sense from a type safety -// point of view it causes a lot of warnings on old code using C header -// files. Here are some typedefs to make the job of silencing warnings -// a bit easier. -// -// The final kick in the teeth is that you can only have extern "C" linkage -// specified at file scope. So these typedefs are here rather than in the -// .hpp for the class (os:Solaris usually) that needs them. - -extern "C" { - typedef int (*int_fnP_thread_t_iP_uP_stack_tP_gregset_t)(thread_t, int*, unsigned *, stack_t*, gregset_t); - typedef int (*int_fnP_thread_t_i_gregset_t)(thread_t, int, gregset_t); - typedef int (*int_fnP_thread_t_i)(thread_t, int); - typedef int (*int_fnP_thread_t)(thread_t); - - typedef int (*int_fnP_cond_tP_mutex_tP_timestruc_tP)(cond_t *cv, mutex_t *mx, timestruc_t *abst); - typedef int (*int_fnP_cond_tP_mutex_tP)(cond_t *cv, mutex_t *mx); - - // typedef for missing API in libc - typedef int (*int_fnP_mutex_tP_i_vP)(mutex_t *, int, void *); - typedef int (*int_fnP_mutex_tP)(mutex_t *); - typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg); - typedef int (*int_fnP_cond_tP)(cond_t *cv); -}; -#endif - -// checking for nanness -#ifdef SOLARIS -#ifdef SPARC -inline int g_isnan(float f) { return isnanf(f); } -#else -// isnanf() broken on Intel Solaris use isnand() -inline int g_isnan(float f) { return isnand(f); } -#endif - -inline int g_isnan(double f) { return isnand(f); } -#elif LINUX -inline int g_isnan(float f) { return isnanf(f); } -inline int g_isnan(double f) { return isnan(f); } -#else -#error "missing platform-specific definition here" -#endif - -// Checking for finiteness - -inline int g_isfinite(jfloat f) { return finite(f); } -inline int g_isfinite(jdouble f) { return finite(f); } - - -// Wide characters - -inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); } - -// Formatting. -#ifdef _LP64 -#define FORMAT64_MODIFIER "l" -#else // !_LP64 -#define FORMAT64_MODIFIER "ll" -#endif // _LP64 - -#define offset_of(klass,field) offsetof(klass,field) - -#define THREAD_LOCAL __thread - -// Inlining support -#define NOINLINE -#define ALWAYSINLINE inline __attribute__((always_inline)) - -// Alignment -#define ATTRIBUTE_ALIGNED(x) __attribute__((aligned(x))) - -#endif // SHARE_UTILITIES_GLOBALDEFINITIONS_SOLSTUDIO_HPP diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -420,14 +420,6 @@ #define NOT_AIX(code) code #endif -#ifdef SOLARIS -#define SOLARIS_ONLY(code) code -#define NOT_SOLARIS(code) -#else -#define SOLARIS_ONLY(code) -#define NOT_SOLARIS(code) code -#endif - #ifdef _WINDOWS #define WINDOWS_ONLY(code) code #define NOT_WINDOWS(code) @@ -509,14 +501,6 @@ #define NOT_S390(code) code #endif -#ifdef SPARC -#define SPARC_ONLY(code) code -#define NOT_SPARC(code) -#else -#define SPARC_ONLY(code) -#define NOT_SPARC(code) code -#endif - #if defined(PPC32) || defined(PPC64) #ifndef PPC #define PPC @@ -601,9 +585,9 @@ // This macro constructs from basename and INCLUDE_SUFFIX_OS / // INCLUDE_SUFFIX_CPU / INCLUDE_SUFFIX_COMPILER, which are set on // the command line, the name of platform dependent files to be included. -// Example: INCLUDE_SUFFIX_OS=_linux / INCLUDE_SUFFIX_CPU=_sparc -// CPU_HEADER_INLINE(macroAssembler) --> macroAssembler_sparc.inline.hpp -// OS_CPU_HEADER(vmStructs) --> vmStructs_linux_sparc.hpp +// Example: INCLUDE_SUFFIX_OS=_linux / INCLUDE_SUFFIX_CPU=_x86 +// CPU_HEADER_INLINE(macroAssembler) --> macroAssembler_x86.inline.hpp +// OS_CPU_HEADER(vmStructs) --> vmStructs_linux_x86.hpp // // basename.hpp / basename.inline.hpp #define CPU_HEADER_H(basename) XSTR(CPU_HEADER_STEM(basename).h) diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -1046,7 +1046,7 @@ #ifndef PRODUCT -#if defined(SOLARIS) || defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE) +#if defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE) #include #include #include diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -83,7 +83,7 @@ "JAVA_HOME", "JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS", "CLASSPATH", "PATH", "USERNAME", - // Env variables that are defined on Solaris/Linux/BSD + // Env variables that are defined on Linux/BSD "LD_LIBRARY_PATH", "LD_PRELOAD", "SHELL", "DISPLAY", "HOSTTYPE", "OSTYPE", "ARCH", "MACHTYPE", "LANG", "LC_ALL", "LC_CTYPE", "TZ", @@ -1594,8 +1594,6 @@ out.print_raw ("# Executing "); #if defined(LINUX) || defined(_ALLBSD_SOURCE) out.print_raw ("/bin/sh -c "); -#elif defined(SOLARIS) - out.print_raw ("/usr/bin/sh -c "); #elif defined(_WINDOWS) out.print_raw ("cmd /C "); #endif @@ -1657,8 +1655,6 @@ tty->print("# Executing "); #if defined(LINUX) tty->print ("/bin/sh -c "); -#elif defined(SOLARIS) - tty->print ("/usr/bin/sh -c "); #endif tty->print_cr("\"%s\"...", cmd); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java --- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java @@ -52,7 +52,7 @@ * *

* This class holds information necessary to create platform-specific binary containers such as - * ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac OS or PEContainer + * ELFContainer for Linux or MachOContainer for Mac OS or PEContainer * for MS Windows operating systems. * *

@@ -552,7 +552,6 @@ String osName = System.getProperty("os.name"); switch (osName) { case "Linux": - case "SunOS": JELFRelocObject elfobj = JELFRelocObject.newInstance(this, outputFileName); elfobj.createELFRelocObject(relocationTable, symbolTable.values()); break; diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java --- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/elf/ElfTargetInfo.java @@ -65,7 +65,7 @@ } osName = System.getProperty("os.name").toLowerCase(); - if (!osName.equals("linux") && !osName.equals("sunos")) { + if (!osName.equals("linux")) { System.out.println("Unsupported Operating System " + osName); osName = "Unknown"; } diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Linker.java @@ -83,15 +83,6 @@ linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName; linkerCheck = linkerPath + " -v"; break; - case "SunOS": - if (name.endsWith(".so")) { - objectFileName = name.substring(0, name.length() - ".so".length()); - } - objectFileName = objectFileName + ".o"; - linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld"; - linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName; - linkerCheck = linkerPath + " -V"; - break; case "Mac OS X": if (name.endsWith(".dylib")) { objectFileName = name.substring(0, name.length() - ".dylib".length()); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/Options.java @@ -72,7 +72,6 @@ switch (osName) { case "Linux": - case "SunOS": ext = "so"; break; case "Mac OS X": diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java @@ -40,7 +40,7 @@ private final PlatformKind wordKind; /** - * The name of this architecture (e.g. "AMD64", "SPARCv9"). + * The name of this architecture (e.g. "AMD64"). */ private final String name; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotJVMCIBackendFactory.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2012, 2016, 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 jdk.vm.ci.hotspot.sparc; - -import static jdk.vm.ci.common.InitTimer.timer; - -import java.util.EnumSet; - -import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.code.stack.StackIntrospection; -import jdk.vm.ci.common.InitTimer; -import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; -import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; -import jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; -import jdk.vm.ci.hotspot.HotSpotStackIntrospection; -import jdk.vm.ci.runtime.JVMCIBackend; -import jdk.vm.ci.sparc.SPARC; -import jdk.vm.ci.sparc.SPARC.CPUFeature; - -public class SPARCHotSpotJVMCIBackendFactory implements HotSpotJVMCIBackendFactory { - - private static TargetDescription createTarget(SPARCHotSpotVMConfig config) { - final int stackFrameAlignment = 16; - final int implicitNullCheckLimit = 4096; - final boolean inlineObjects = false; - Architecture arch = new SPARC(computeFeatures(config)); - return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); - } - - protected HotSpotCodeCacheProvider createCodeCache(HotSpotJVMCIRuntime runtime, TargetDescription target, RegisterConfig regConfig) { - return new HotSpotCodeCacheProvider(runtime, target, regConfig); - } - - private static EnumSet computeFeatures(SPARCHotSpotVMConfig config) { - EnumSet features = EnumSet.noneOf(CPUFeature.class); - - if ((config.vmVersionFeatures & 1L << config.sparc_ADI) != 0) { - features.add(CPUFeature.ADI); - } - if ((config.vmVersionFeatures & 1L << config.sparc_AES) != 0) { - features.add(CPUFeature.AES); - } - if ((config.vmVersionFeatures & 1L << config.sparc_BLK_INIT) != 0) { - features.add(CPUFeature.BLK_INIT); - } - if ((config.vmVersionFeatures & 1L << config.sparc_CAMELLIA) != 0) { - features.add(CPUFeature.CAMELLIA); - } - if ((config.vmVersionFeatures & 1L << config.sparc_CBCOND) != 0) { - features.add(CPUFeature.CBCOND); - } - if ((config.vmVersionFeatures & 1L << config.sparc_CRC32C) != 0) { - features.add(CPUFeature.CRC32C); - } - if ((config.vmVersionFeatures & 1L << config.sparc_DES) != 0) { - features.add(CPUFeature.DES); - } - if ((config.vmVersionFeatures & 1L << config.sparc_DICTUNP) != 0) { - features.add(CPUFeature.DICTUNP); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FMAF) != 0) { - features.add(CPUFeature.FMAF); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FPCMPSHL) != 0) { - features.add(CPUFeature.FPCMPSHL); - } - if ((config.vmVersionFeatures & 1L << config.sparc_HPC) != 0) { - features.add(CPUFeature.HPC); - } - if ((config.vmVersionFeatures & 1L << config.sparc_IMA) != 0) { - features.add(CPUFeature.IMA); - } - if ((config.vmVersionFeatures & 1L << config.sparc_KASUMI) != 0) { - features.add(CPUFeature.KASUMI); - } - if ((config.vmVersionFeatures & 1L << config.sparc_MD5) != 0) { - features.add(CPUFeature.MD5); - } - if ((config.vmVersionFeatures & 1L << config.sparc_MME) != 0) { - features.add(CPUFeature.MME); - } - if ((config.vmVersionFeatures & 1L << config.sparc_MONT) != 0) { - features.add(CPUFeature.MONT); - } - if ((config.vmVersionFeatures & 1L << config.sparc_MPMUL) != 0) { - features.add(CPUFeature.MPMUL); - } - if ((config.vmVersionFeatures & 1L << config.sparc_MWAIT) != 0) { - features.add(CPUFeature.MWAIT); - } - if ((config.vmVersionFeatures & 1L << config.sparc_PAUSE) != 0) { - features.add(CPUFeature.PAUSE); - } - if ((config.vmVersionFeatures & 1L << config.sparc_PAUSE_NSEC) != 0) { - features.add(CPUFeature.PAUSE_NSEC); - } - if ((config.vmVersionFeatures & 1L << config.sparc_POPC) != 0) { - features.add(CPUFeature.POPC); - } - if ((config.vmVersionFeatures & 1L << config.sparc_RLE) != 0) { - features.add(CPUFeature.RLE); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SHA1) != 0) { - features.add(CPUFeature.SHA1); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SHA256) != 0) { - features.add(CPUFeature.SHA256); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SHA3) != 0) { - features.add(CPUFeature.SHA3); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SHA512) != 0) { - features.add(CPUFeature.SHA512); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SPARC5) != 0) { - features.add(CPUFeature.SPARC5); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SPARC5B) != 0) { - features.add(CPUFeature.SPARC5B); - } - if ((config.vmVersionFeatures & 1L << config.sparc_SPARC6) != 0) { - features.add(CPUFeature.SPARC6); - } - if ((config.vmVersionFeatures & 1L << config.sparc_V9) != 0) { - features.add(CPUFeature.V9); - } - if ((config.vmVersionFeatures & 1L << config.sparc_VAMASK) != 0) { - features.add(CPUFeature.VAMASK); - } - if ((config.vmVersionFeatures & 1L << config.sparc_VIS1) != 0) { - features.add(CPUFeature.VIS1); - } - if ((config.vmVersionFeatures & 1L << config.sparc_VIS2) != 0) { - features.add(CPUFeature.VIS2); - } - if ((config.vmVersionFeatures & 1L << config.sparc_VIS3) != 0) { - features.add(CPUFeature.VIS3); - } - if ((config.vmVersionFeatures & 1L << config.sparc_VIS3B) != 0) { - features.add(CPUFeature.VIS3B); - } - if ((config.vmVersionFeatures & 1L << config.sparc_VIS3C) != 0) { - features.add(CPUFeature.VIS3C); - } - if ((config.vmVersionFeatures & 1L << config.sparc_XMONT) != 0) { - features.add(CPUFeature.XMONT); - } - if ((config.vmVersionFeatures & 1L << config.sparc_XMPMUL) != 0) { - features.add(CPUFeature.XMPMUL); - } - - if ((config.vmVersionFeatures & 1L << config.sparc_BLK_ZEROING) != 0) { - features.add(CPUFeature.BLK_ZEROING); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FAST_BIS) != 0) { - features.add(CPUFeature.FAST_BIS); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FAST_CMOVE) != 0) { - features.add(CPUFeature.FAST_CMOVE); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FAST_IDIV) != 0) { - features.add(CPUFeature.FAST_IDIV); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FAST_IND_BR) != 0) { - features.add(CPUFeature.FAST_IND_BR); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FAST_LD) != 0) { - features.add(CPUFeature.FAST_LD); - } - if ((config.vmVersionFeatures & 1L << config.sparc_FAST_RDPC) != 0) { - features.add(CPUFeature.FAST_RDPC); - } - - return features; - } - - @Override - public String getArchitecture() { - return "SPARC"; - } - - @Override - public String toString() { - return "JVMCIBackend:" + getArchitecture(); - } - - @Override - @SuppressWarnings("try") - public JVMCIBackend createJVMCIBackend(HotSpotJVMCIRuntime runtime, JVMCIBackend host) { - assert host == null; - SPARCHotSpotVMConfig config = new SPARCHotSpotVMConfig(runtime.getConfigStore()); - TargetDescription target = createTarget(config); - - HotSpotMetaAccessProvider metaAccess = new HotSpotMetaAccessProvider(runtime); - RegisterConfig regConfig = new SPARCHotSpotRegisterConfig(target, config.useCompressedOops); - HotSpotCodeCacheProvider codeCache = createCodeCache(runtime, target, regConfig); - HotSpotConstantReflectionProvider constantReflection = new HotSpotConstantReflectionProvider(runtime); - StackIntrospection stackIntrospection = new HotSpotStackIntrospection(runtime); - try (InitTimer rt = timer("instantiate backend")) { - return createBackend(metaAccess, codeCache, constantReflection, stackIntrospection); - } - } - - protected JVMCIBackend createBackend(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, HotSpotConstantReflectionProvider constantReflection, - StackIntrospection stackIntrospection) { - return new JVMCIBackend(metaAccess, codeCache, constantReflection, stackIntrospection); - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotRegisterConfig.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (c) 2013, 2016, 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 jdk.vm.ci.hotspot.sparc; - -import static jdk.vm.ci.meta.JavaKind.Void; -import static jdk.vm.ci.meta.Value.ILLEGAL; -import static jdk.vm.ci.sparc.SPARC.REGISTER_SAFE_AREA_SIZE; -import static jdk.vm.ci.sparc.SPARC.d0; -import static jdk.vm.ci.sparc.SPARC.d10; -import static jdk.vm.ci.sparc.SPARC.d12; -import static jdk.vm.ci.sparc.SPARC.d14; -import static jdk.vm.ci.sparc.SPARC.d16; -import static jdk.vm.ci.sparc.SPARC.d18; -import static jdk.vm.ci.sparc.SPARC.d2; -import static jdk.vm.ci.sparc.SPARC.d20; -import static jdk.vm.ci.sparc.SPARC.d22; -import static jdk.vm.ci.sparc.SPARC.d24; -import static jdk.vm.ci.sparc.SPARC.d26; -import static jdk.vm.ci.sparc.SPARC.d28; -import static jdk.vm.ci.sparc.SPARC.d30; -import static jdk.vm.ci.sparc.SPARC.d4; -import static jdk.vm.ci.sparc.SPARC.d6; -import static jdk.vm.ci.sparc.SPARC.d8; -import static jdk.vm.ci.sparc.SPARC.f0; -import static jdk.vm.ci.sparc.SPARC.f1; -import static jdk.vm.ci.sparc.SPARC.f11; -import static jdk.vm.ci.sparc.SPARC.f13; -import static jdk.vm.ci.sparc.SPARC.f15; -import static jdk.vm.ci.sparc.SPARC.f17; -import static jdk.vm.ci.sparc.SPARC.f19; -import static jdk.vm.ci.sparc.SPARC.f2; -import static jdk.vm.ci.sparc.SPARC.f21; -import static jdk.vm.ci.sparc.SPARC.f23; -import static jdk.vm.ci.sparc.SPARC.f25; -import static jdk.vm.ci.sparc.SPARC.f27; -import static jdk.vm.ci.sparc.SPARC.f29; -import static jdk.vm.ci.sparc.SPARC.f3; -import static jdk.vm.ci.sparc.SPARC.f31; -import static jdk.vm.ci.sparc.SPARC.f4; -import static jdk.vm.ci.sparc.SPARC.f5; -import static jdk.vm.ci.sparc.SPARC.f6; -import static jdk.vm.ci.sparc.SPARC.f7; -import static jdk.vm.ci.sparc.SPARC.f9; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARC.g2; -import static jdk.vm.ci.sparc.SPARC.g6; -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i1; -import static jdk.vm.ci.sparc.SPARC.i2; -import static jdk.vm.ci.sparc.SPARC.i3; -import static jdk.vm.ci.sparc.SPARC.i4; -import static jdk.vm.ci.sparc.SPARC.i5; -import static jdk.vm.ci.sparc.SPARC.i6; -import static jdk.vm.ci.sparc.SPARC.i7; -import static jdk.vm.ci.sparc.SPARC.l0; -import static jdk.vm.ci.sparc.SPARC.l1; -import static jdk.vm.ci.sparc.SPARC.l2; -import static jdk.vm.ci.sparc.SPARC.l3; -import static jdk.vm.ci.sparc.SPARC.l4; -import static jdk.vm.ci.sparc.SPARC.l5; -import static jdk.vm.ci.sparc.SPARC.l6; -import static jdk.vm.ci.sparc.SPARC.l7; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o1; -import static jdk.vm.ci.sparc.SPARC.o2; -import static jdk.vm.ci.sparc.SPARC.o3; -import static jdk.vm.ci.sparc.SPARC.o4; -import static jdk.vm.ci.sparc.SPARC.o5; -import static jdk.vm.ci.sparc.SPARC.sp; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.CallingConvention.Type; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterArray; -import jdk.vm.ci.code.RegisterAttributes; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.StackSlot; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.code.ValueKindFactory; -import jdk.vm.ci.common.JVMCIError; -import jdk.vm.ci.hotspot.HotSpotCallingConventionType; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.ValueKind; -import jdk.vm.ci.sparc.SPARC; - -public class SPARCHotSpotRegisterConfig implements RegisterConfig { - - private final TargetDescription target; - - private final RegisterArray allocatable; - - private final RegisterAttributes[] attributesMap; - - @Override - public RegisterArray getAllocatableRegisters() { - return allocatable; - } - - @Override - public RegisterArray filterAllocatableRegisters(PlatformKind kind, RegisterArray registers) { - ArrayList list = new ArrayList<>(); - for (Register reg : registers) { - if (target.arch.canStoreValue(reg.getRegisterCategory(), kind)) { - list.add(reg); - } - } - return new RegisterArray(list); - } - - @Override - public RegisterAttributes[] getAttributesMap() { - return attributesMap.clone(); - } - - private final RegisterArray cpuCallerParameterRegisters = new RegisterArray(o0, o1, o2, o3, o4, o5); - private final RegisterArray cpuCalleeParameterRegisters = new RegisterArray(i0, i1, i2, i3, i4, i5); - - private final RegisterArray fpuFloatJavaParameterRegisters = new RegisterArray(f0, f1, f2, f3, f4, f5, f6, f7); - private final RegisterArray fpuDoubleJavaParameterRegisters = new RegisterArray(d0, null, d2, null, d4, null, d6, null); - - // @formatter:off - private final RegisterArray fpuFloatNativeParameterRegisters = new RegisterArray( - f1, f3, f5, f7, f9, f11, f13, f15, - f17, f19, f21, f23, f25, f27, f29, f31); - - private final RegisterArray fpuDoubleNativeParameterRegisters = new RegisterArray( - d0, d2, d4, d6, d8, d10, d12, d14, - d16, d18, d20, d22, d24, d26, d28, d30); - - private final RegisterArray callerSaveRegisters; - - /** - * This lists all L and I registers which are saved in the register window. - */ - private final RegisterArray windowSaveRegisters = new RegisterArray( - l0, l1, l2, l3, l4, l5, l6, l7, - i0, i1, i2, i3, i4, i5, i6, i7); - // @formatter:on - - private static final RegisterArray reservedRegisters = new RegisterArray(sp, g0, g2); - - private static RegisterArray initAllocatable(Architecture arch, boolean reserveForHeapBase) { - RegisterArray allRegisters = arch.getAvailableValueRegisters(); - Register[] registers = new Register[allRegisters.size() - reservedRegisters.size() - (reserveForHeapBase ? 1 : 0)]; - List reservedRegistersList = reservedRegisters.asList(); - - int idx = 0; - for (Register reg : allRegisters) { - if (reservedRegistersList.contains(reg)) { - // skip reserved registers - continue; - } - if (reserveForHeapBase && reg.equals(g6)) { - // skip heap base register - continue; - } - - registers[idx++] = reg; - } - - assert idx == registers.length; - return new RegisterArray(registers); - } - - public SPARCHotSpotRegisterConfig(TargetDescription target, boolean useCompressedOops) { - this(target, initAllocatable(target.arch, useCompressedOops)); - } - - public SPARCHotSpotRegisterConfig(TargetDescription target, RegisterArray allocatable) { - this.target = target; - this.allocatable = allocatable; - HashSet callerSaveSet = new HashSet<>(target.arch.getAvailableValueRegisters().asList()); - for (Register cs : windowSaveRegisters) { - callerSaveSet.remove(cs); - } - this.callerSaveRegisters = new RegisterArray(callerSaveSet); - attributesMap = RegisterAttributes.createMap(this, SPARC.allRegisters); - } - - @Override - public RegisterArray getCallerSaveRegisters() { - return callerSaveRegisters; - } - - @Override - public RegisterArray getCalleeSaveRegisters() { - return null; - } - - @Override - public boolean areAllAllocatableRegistersCallerSaved() { - return false; - } - - @Override - public CallingConvention getCallingConvention(Type type, JavaType returnType, JavaType[] parameterTypes, ValueKindFactory valueKindFactory) { - HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; - if (type == HotSpotCallingConventionType.JavaCall || type == HotSpotCallingConventionType.NativeCall) { - return callingConvention(cpuCallerParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory); - } - if (type == HotSpotCallingConventionType.JavaCallee) { - return callingConvention(cpuCalleeParameterRegisters, returnType, parameterTypes, hotspotType, valueKindFactory); - } - throw JVMCIError.shouldNotReachHere(); - } - - @Override - public RegisterArray getCallingConventionRegisters(Type type, JavaKind kind) { - HotSpotCallingConventionType hotspotType = (HotSpotCallingConventionType) type; - switch (kind) { - case Boolean: - case Byte: - case Short: - case Char: - case Int: - case Long: - case Object: - return hotspotType == HotSpotCallingConventionType.JavaCallee ? cpuCalleeParameterRegisters : cpuCallerParameterRegisters; - case Double: - case Float: - return fpuFloatJavaParameterRegisters; - default: - throw JVMCIError.shouldNotReachHere("Unknown JavaKind " + kind); - } - } - - private CallingConvention callingConvention(RegisterArray generalParameterRegisters, JavaType returnType, JavaType[] parameterTypes, HotSpotCallingConventionType type, - ValueKindFactory valueKindFactory) { - AllocatableValue[] locations = new AllocatableValue[parameterTypes.length]; - - int currentGeneral = 0; - int currentFloating = 0; - int currentStackOffset = 0; - boolean isNative = type == HotSpotCallingConventionType.NativeCall; - - for (int i = 0; i < parameterTypes.length; i++) { - final JavaKind kind = parameterTypes[i].getJavaKind().getStackKind(); - if (isNative) { - RegisterArray registerSet; - switch (kind) { - case Byte: - case Boolean: - case Short: - case Char: - case Int: - case Long: - case Object: - registerSet = generalParameterRegisters; - break; - case Double: - registerSet = fpuDoubleNativeParameterRegisters; - break; - case Float: - registerSet = fpuFloatNativeParameterRegisters; - break; - default: - throw JVMCIError.shouldNotReachHere(); - } - if (i < registerSet.size()) { - locations[i] = registerSet.get(i).asValue(valueKindFactory.getValueKind(kind)); - currentStackOffset += target.arch.getWordSize(); - } - } else { - switch (kind) { - case Byte: - case Boolean: - case Short: - case Char: - case Int: - case Long: - case Object: - if (currentGeneral < generalParameterRegisters.size()) { - Register register = generalParameterRegisters.get(currentGeneral++); - locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); - } - break; - case Double: - if (currentFloating < fpuFloatJavaParameterRegisters.size()) { - if (currentFloating % 2 != 0) { - // Make register number even to be a double reg - currentFloating++; - } - Register register = fpuDoubleJavaParameterRegisters.get(currentFloating); - currentFloating += 2; // Only every second is a double register - locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); - } - break; - case Float: - if (currentFloating < fpuFloatJavaParameterRegisters.size()) { - Register register = fpuFloatJavaParameterRegisters.get(currentFloating++); - locations[i] = register.asValue(valueKindFactory.getValueKind(kind)); - } - break; - default: - throw JVMCIError.shouldNotReachHere(); - } - } - - if (locations[i] == null) { - ValueKind valueKind = valueKindFactory.getValueKind(kind); - int typeSize = valueKind.getPlatformKind().getSizeInBytes(); - if (isNative) { - currentStackOffset += target.arch.getWordSize() - typeSize; - } - currentStackOffset = roundUp(currentStackOffset, typeSize); - int slotOffset = currentStackOffset + REGISTER_SAFE_AREA_SIZE; - locations[i] = StackSlot.get(valueKind, slotOffset, !type.out); - currentStackOffset += typeSize; - } - } - - JavaKind returnKind = returnType == null ? Void : returnType.getJavaKind(); - AllocatableValue returnLocation = returnKind == Void ? ILLEGAL : getReturnRegister(returnKind, type).asValue(valueKindFactory.getValueKind(returnKind.getStackKind())); - return new CallingConvention(currentStackOffset, returnLocation, locations); - } - - private static int roundUp(int number, int mod) { - return ((number + mod - 1) / mod) * mod; - } - - @Override - public Register getReturnRegister(JavaKind kind) { - return getReturnRegister(kind, HotSpotCallingConventionType.JavaCallee); - } - - private static Register getReturnRegister(JavaKind kind, HotSpotCallingConventionType type) { - switch (kind) { - case Boolean: - case Byte: - case Char: - case Short: - case Int: - case Long: - case Object: - return type == HotSpotCallingConventionType.JavaCallee ? i0 : o0; - case Float: - return f0; - case Double: - return d0; - case Void: - case Illegal: - return null; - default: - throw new UnsupportedOperationException("no return register for type " + kind); - } - } - - @Override - public Register getFrameRegister() { - return sp; - } - - @Override - public String toString() { - return String.format("Allocatable: " + getAllocatableRegisters() + "%n" + "CallerSave: " + getCallerSaveRegisters() + "%n"); - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/SPARCHotSpotVMConfig.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2016, 2018, 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 jdk.vm.ci.hotspot.sparc; - -import jdk.vm.ci.hotspot.HotSpotVMConfigAccess; -import jdk.vm.ci.hotspot.HotSpotVMConfigStore; - -/** - * Used to access native configuration details. - * - * All non-static, public fields in this class are so that they can be compiled as constants. - */ -class SPARCHotSpotVMConfig extends HotSpotVMConfigAccess { - - SPARCHotSpotVMConfig(HotSpotVMConfigStore config) { - super(config); - } - - final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); - - // @formatter:off - // CPU capabilities: - // - // FIXME: Using a 64-bit value is insufficient to support future capability - // sets (including co-processor capabilities such as DAX). - final long vmVersionFeatures = getFieldValue("Abstract_VM_Version::_features", Long.class, "uint64_t"); - - // - // SPARC specific values: - // - // NOTE: Values changed into an enumeration (that do indeed fit within a - // 32-bit integer) instead of the exported (64-bit wide) bit-masks. - final int sparc_ADI = getConstant("VM_Version::ISA_ADI", Integer.class); - final int sparc_AES = getConstant("VM_Version::ISA_AES", Integer.class); - final int sparc_BLK_INIT = getConstant("VM_Version::ISA_BLK_INIT", Integer.class); - final int sparc_CAMELLIA = getConstant("VM_Version::ISA_CAMELLIA", Integer.class); - final int sparc_CBCOND = getConstant("VM_Version::ISA_CBCOND", Integer.class); - final int sparc_CRC32C = getConstant("VM_Version::ISA_CRC32C", Integer.class); - final int sparc_DES = getConstant("VM_Version::ISA_DES", Integer.class); - final int sparc_DICTUNP = getConstant("VM_Version::ISA_DICTUNP", Integer.class); - final int sparc_FMAF = getConstant("VM_Version::ISA_FMAF", Integer.class); - final int sparc_FPCMPSHL = getConstant("VM_Version::ISA_FPCMPSHL", Integer.class); - final int sparc_HPC = getConstant("VM_Version::ISA_HPC", Integer.class); - final int sparc_IMA = getConstant("VM_Version::ISA_IMA", Integer.class); - final int sparc_KASUMI = getConstant("VM_Version::ISA_KASUMI", Integer.class); - final int sparc_MD5 = getConstant("VM_Version::ISA_MD5", Integer.class); - final int sparc_MME = getConstant("VM_Version::ISA_MME", Integer.class); - final int sparc_MONT = getConstant("VM_Version::ISA_MONT", Integer.class); - final int sparc_MPMUL = getConstant("VM_Version::ISA_MPMUL", Integer.class); - final int sparc_MWAIT = getConstant("VM_Version::ISA_MWAIT", Integer.class); - final int sparc_PAUSE = getConstant("VM_Version::ISA_PAUSE", Integer.class); - final int sparc_PAUSE_NSEC = getConstant("VM_Version::ISA_PAUSE_NSEC", Integer.class); - final int sparc_POPC = getConstant("VM_Version::ISA_POPC", Integer.class); - final int sparc_RLE = getConstant("VM_Version::ISA_RLE", Integer.class); - final int sparc_SHA1 = getConstant("VM_Version::ISA_SHA1", Integer.class); - final int sparc_SHA256 = getConstant("VM_Version::ISA_SHA256", Integer.class); - final int sparc_SHA3 = getConstant("VM_Version::ISA_SHA3", Integer.class); - final int sparc_SHA512 = getConstant("VM_Version::ISA_SHA512", Integer.class); - final int sparc_SPARC5 = getConstant("VM_Version::ISA_SPARC5", Integer.class); - final int sparc_SPARC5B = getConstant("VM_Version::ISA_SPARC5B", Integer.class); - final int sparc_SPARC6 = getConstant("VM_Version::ISA_SPARC6", Integer.class); - final int sparc_V9 = getConstant("VM_Version::ISA_V9", Integer.class); - final int sparc_VAMASK = getConstant("VM_Version::ISA_VAMASK", Integer.class); - final int sparc_VIS1 = getConstant("VM_Version::ISA_VIS1", Integer.class); - final int sparc_VIS2 = getConstant("VM_Version::ISA_VIS2", Integer.class); - final int sparc_VIS3 = getConstant("VM_Version::ISA_VIS3", Integer.class); - final int sparc_VIS3B = getConstant("VM_Version::ISA_VIS3B", Integer.class); - final int sparc_VIS3C = getConstant("VM_Version::ISA_VIS3C", Integer.class); - final int sparc_XMONT = getConstant("VM_Version::ISA_XMONT", Integer.class); - final int sparc_XMPMUL = getConstant("VM_Version::ISA_XMPMUL", Integer.class); - - final int sparc_BLK_ZEROING = getConstant("VM_Version::CPU_BLK_ZEROING", Integer.class); - final int sparc_FAST_BIS = getConstant("VM_Version::CPU_FAST_BIS", Integer.class); - final int sparc_FAST_CMOVE = getConstant("VM_Version::CPU_FAST_CMOVE", Integer.class); - final int sparc_FAST_IDIV = getConstant("VM_Version::CPU_FAST_IDIV", Integer.class); - final int sparc_FAST_IND_BR = getConstant("VM_Version::CPU_FAST_IND_BR", Integer.class); - final int sparc_FAST_LD = getConstant("VM_Version::CPU_FAST_LD", Integer.class); - final int sparc_FAST_RDPC = getConstant("VM_Version::CPU_FAST_RDPC", Integer.class); - - final boolean useBlockZeroing = getFlag("UseBlockZeroing", Boolean.class); - final int blockZeroingLowLimit = getFlag("BlockZeroingLowLimit", Integer.class); - // @formatter:on -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/package-info.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.sparc/src/jdk/vm/ci/hotspot/sparc/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018, 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 SPARC HotSpot specific portions of the JVMCI API. - */ -package jdk.vm.ci.hotspot.sparc; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -58,8 +58,6 @@ case "x86_64": return "amd64"; - case "sparcv9": - return "sparc"; default: return arch; } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARC.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2013, 2019, 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 jdk.vm.ci.sparc; - -import static java.nio.ByteOrder.BIG_ENDIAN; -import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD; -import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; -import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; - -import java.util.Set; - -import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.Register.RegisterCategory; -import jdk.vm.ci.code.RegisterArray; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.PlatformKind; - -/** - * Represents the SPARC architecture. - */ -public class SPARC extends Architecture { - - public static final RegisterCategory CPU = new RegisterCategory("CPU"); - public static final RegisterCategory FPUs = new RegisterCategory("FPUs"); - public static final RegisterCategory FPUd = new RegisterCategory("FPUd"); - public static final RegisterCategory FPUq = new RegisterCategory("FPUq"); - - // General purpose registers - public static final Register g0 = new Register(0, 0, "g0", CPU); - public static final Register g1 = new Register(1, 1, "g1", CPU); - public static final Register g2 = new Register(2, 2, "g2", CPU); - public static final Register g3 = new Register(3, 3, "g3", CPU); - public static final Register g4 = new Register(4, 4, "g4", CPU); - public static final Register g5 = new Register(5, 5, "g5", CPU); - public static final Register g6 = new Register(6, 6, "g6", CPU); - public static final Register g7 = new Register(7, 7, "g7", CPU); - - public static final Register o0 = new Register(8, 8, "o0", CPU); - public static final Register o1 = new Register(9, 9, "o1", CPU); - public static final Register o2 = new Register(10, 10, "o2", CPU); - public static final Register o3 = new Register(11, 11, "o3", CPU); - public static final Register o4 = new Register(12, 12, "o4", CPU); - public static final Register o5 = new Register(13, 13, "o5", CPU); - public static final Register o6 = new Register(14, 14, "o6", CPU); - public static final Register o7 = new Register(15, 15, "o7", CPU); - - public static final Register l0 = new Register(16, 16, "l0", CPU); - public static final Register l1 = new Register(17, 17, "l1", CPU); - public static final Register l2 = new Register(18, 18, "l2", CPU); - public static final Register l3 = new Register(19, 19, "l3", CPU); - public static final Register l4 = new Register(20, 20, "l4", CPU); - public static final Register l5 = new Register(21, 21, "l5", CPU); - public static final Register l6 = new Register(22, 22, "l6", CPU); - public static final Register l7 = new Register(23, 23, "l7", CPU); - - public static final Register i0 = new Register(24, 24, "i0", CPU); - public static final Register i1 = new Register(25, 25, "i1", CPU); - public static final Register i2 = new Register(26, 26, "i2", CPU); - public static final Register i3 = new Register(27, 27, "i3", CPU); - public static final Register i4 = new Register(28, 28, "i4", CPU); - public static final Register i5 = new Register(29, 29, "i5", CPU); - public static final Register i6 = new Register(30, 30, "i6", CPU); - public static final Register i7 = new Register(31, 31, "i7", CPU); - - public static final Register sp = o6; - public static final Register fp = i6; - - // Floating point registers - public static final Register f0 = new Register(32, 0, "f0", FPUs); - public static final Register f1 = new Register(33, 1, "f1", FPUs); - public static final Register f2 = new Register(34, 2, "f2", FPUs); - public static final Register f3 = new Register(35, 3, "f3", FPUs); - public static final Register f4 = new Register(36, 4, "f4", FPUs); - public static final Register f5 = new Register(37, 5, "f5", FPUs); - public static final Register f6 = new Register(38, 6, "f6", FPUs); - public static final Register f7 = new Register(39, 7, "f7", FPUs); - - public static final Register f8 = new Register(40, 8, "f8", FPUs); - public static final Register f9 = new Register(41, 9, "f9", FPUs); - public static final Register f10 = new Register(42, 10, "f10", FPUs); - public static final Register f11 = new Register(43, 11, "f11", FPUs); - public static final Register f12 = new Register(44, 12, "f12", FPUs); - public static final Register f13 = new Register(45, 13, "f13", FPUs); - public static final Register f14 = new Register(46, 14, "f14", FPUs); - public static final Register f15 = new Register(47, 15, "f15", FPUs); - - public static final Register f16 = new Register(48, 16, "f16", FPUs); - public static final Register f17 = new Register(49, 17, "f17", FPUs); - public static final Register f18 = new Register(50, 18, "f18", FPUs); - public static final Register f19 = new Register(51, 19, "f19", FPUs); - public static final Register f20 = new Register(52, 20, "f20", FPUs); - public static final Register f21 = new Register(53, 21, "f21", FPUs); - public static final Register f22 = new Register(54, 22, "f22", FPUs); - public static final Register f23 = new Register(55, 23, "f23", FPUs); - - public static final Register f24 = new Register(56, 24, "f24", FPUs); - public static final Register f25 = new Register(57, 25, "f25", FPUs); - public static final Register f26 = new Register(58, 26, "f26", FPUs); - public static final Register f27 = new Register(59, 27, "f27", FPUs); - public static final Register f28 = new Register(60, 28, "f28", FPUs); - public static final Register f29 = new Register(61, 29, "f29", FPUs); - public static final Register f30 = new Register(62, 30, "f30", FPUs); - public static final Register f31 = new Register(63, 31, "f31", FPUs); - - // Double precision registers - public static final Register d0 = new Register(64, getDoubleEncoding(0), "d0", FPUd); - public static final Register d2 = new Register(65, getDoubleEncoding(2), "d2", FPUd); - public static final Register d4 = new Register(66, getDoubleEncoding(4), "d4", FPUd); - public static final Register d6 = new Register(67, getDoubleEncoding(6), "d6", FPUd); - public static final Register d8 = new Register(68, getDoubleEncoding(8), "d8", FPUd); - public static final Register d10 = new Register(69, getDoubleEncoding(10), "d10", FPUd); - public static final Register d12 = new Register(70, getDoubleEncoding(12), "d12", FPUd); - public static final Register d14 = new Register(71, getDoubleEncoding(14), "d14", FPUd); - - public static final Register d16 = new Register(72, getDoubleEncoding(16), "d16", FPUd); - public static final Register d18 = new Register(73, getDoubleEncoding(18), "d18", FPUd); - public static final Register d20 = new Register(74, getDoubleEncoding(20), "d20", FPUd); - public static final Register d22 = new Register(75, getDoubleEncoding(22), "d22", FPUd); - public static final Register d24 = new Register(76, getDoubleEncoding(24), "d24", FPUd); - public static final Register d26 = new Register(77, getDoubleEncoding(26), "d26", FPUd); - public static final Register d28 = new Register(78, getDoubleEncoding(28), "d28", FPUd); - public static final Register d30 = new Register(79, getDoubleEncoding(28), "d28", FPUd); - - public static final Register d32 = new Register(80, getDoubleEncoding(32), "d32", FPUd); - public static final Register d34 = new Register(81, getDoubleEncoding(34), "d34", FPUd); - public static final Register d36 = new Register(82, getDoubleEncoding(36), "d36", FPUd); - public static final Register d38 = new Register(83, getDoubleEncoding(38), "d38", FPUd); - public static final Register d40 = new Register(84, getDoubleEncoding(40), "d40", FPUd); - public static final Register d42 = new Register(85, getDoubleEncoding(42), "d42", FPUd); - public static final Register d44 = new Register(86, getDoubleEncoding(44), "d44", FPUd); - public static final Register d46 = new Register(87, getDoubleEncoding(46), "d46", FPUd); - - public static final Register d48 = new Register(88, getDoubleEncoding(48), "d48", FPUd); - public static final Register d50 = new Register(89, getDoubleEncoding(50), "d50", FPUd); - public static final Register d52 = new Register(90, getDoubleEncoding(52), "d52", FPUd); - public static final Register d54 = new Register(91, getDoubleEncoding(54), "d54", FPUd); - public static final Register d56 = new Register(92, getDoubleEncoding(56), "d56", FPUd); - public static final Register d58 = new Register(93, getDoubleEncoding(58), "d58", FPUd); - public static final Register d60 = new Register(94, getDoubleEncoding(60), "d60", FPUd); - public static final Register d62 = new Register(95, getDoubleEncoding(62), "d62", FPUd); - - // Quad precision registers - public static final Register q0 = new Register(96, getQuadncoding(0), "q0", FPUq); - public static final Register q4 = new Register(97, getQuadncoding(4), "q4", FPUq); - public static final Register q8 = new Register(98, getQuadncoding(8), "q8", FPUq); - public static final Register q12 = new Register(99, getQuadncoding(12), "q12", FPUq); - public static final Register q16 = new Register(100, getQuadncoding(16), "q16", FPUq); - public static final Register q20 = new Register(101, getQuadncoding(20), "q20", FPUq); - public static final Register q24 = new Register(102, getQuadncoding(24), "q24", FPUq); - public static final Register q28 = new Register(103, getQuadncoding(28), "q28", FPUq); - - public static final Register q32 = new Register(104, getQuadncoding(32), "q32", FPUq); - public static final Register q36 = new Register(105, getQuadncoding(36), "q36", FPUq); - public static final Register q40 = new Register(106, getQuadncoding(40), "q40", FPUq); - public static final Register q44 = new Register(107, getQuadncoding(44), "q44", FPUq); - public static final Register q48 = new Register(108, getQuadncoding(48), "q48", FPUq); - public static final Register q52 = new Register(109, getQuadncoding(52), "q52", FPUq); - public static final Register q56 = new Register(110, getQuadncoding(56), "q56", FPUq); - public static final Register q60 = new Register(111, getQuadncoding(60), "q60", FPUq); - - // @formatter:off - public static final RegisterArray cpuRegisters = new RegisterArray( - g0, g1, g2, g3, g4, g5, g6, g7, - o0, o1, o2, o3, o4, o5, o6, o7, - l0, l1, l2, l3, l4, l5, l6, l7, - i0, i1, i2, i3, i4, i5, i6, i7 - ); - - public static final RegisterArray fpusRegisters = new RegisterArray( - f0, f1, f2, f3, f4, f5, f6, f7, - f8, f9, f10, f11, f12, f13, f14, f15, - f16, f17, f18, f19, f20, f21, f22, f23, - f24, f25, f26, f27, f28, f29, f30, f31 - ); - - public static final RegisterArray fpudRegisters = new RegisterArray( - d0, d2, d4, d6, d8, d10, d12, d14, - d16, d18, d20, d22, d24, d26, d28, d30, - d32, d34, d36, d38, d40, d42, d44, d46, - d48, d50, d52, d54, d56, d58, d60, d62 - ); - - public static final RegisterArray fpuqRegisters = new RegisterArray( - q0, q4, q8, q12, - q16, q20, q24, q28, - q32, q36, q40, q44, - q48, q52, q56, q60 - ); - - public static final RegisterArray allRegisters = new RegisterArray( - g0, g1, g2, g3, g4, g5, g6, g7, - o0, o1, o2, o3, o4, o5, o6, o7, - l0, l1, l2, l3, l4, l5, l6, l7, - i0, i1, i2, i3, i4, i5, i6, i7, - - f0, f1, f2, f3, f4, f5, f6, f7, - f8, f9, f10, f11, f12, f13, f14, f15, - f16, f17, f18, f19, f20, f21, f22, f23, - f24, f25, f26, f27, f28, f29, f30, f31, - - d0, d2, d4, d6, d8, d10, d12, d14, - d16, d18, d20, d22, d24, d26, d28, d30, - d32, d34, d36, d38, d40, d42, d44, d46, - d48, d50, d52, d54, d56, d58, d60, d62, - - q0, q4, q8, q12, - q16, q20, q24, q28, - q32, q36, q40, q44, - q48, q52, q56, q60 - ); - // @formatter:on - - /** - * Stack bias for stack and frame pointer loads. - */ - public static final int STACK_BIAS = 0x7ff; - - /** - * Size to keep free for flushing the register-window to stack. - */ - public static final int REGISTER_SAFE_AREA_SIZE = 128; - - public final Set features; - - public SPARC(Set features) { - super("SPARC", SPARCKind.XWORD, BIG_ENDIAN, false, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, 8); - this.features = features; - } - - @Override - public RegisterArray getAvailableValueRegisters() { - return allRegisters; - } - - @Override - public boolean canStoreValue(RegisterCategory category, PlatformKind kind) { - SPARCKind sparcKind = (SPARCKind) kind; - switch (sparcKind) { - case BYTE: - case HWORD: - case WORD: - case XWORD: - return CPU.equals(category); - case SINGLE: - case V32_BYTE: - case V32_HWORD: - return FPUs.equals(category); - case DOUBLE: - case V64_BYTE: - case V64_HWORD: - case V64_WORD: - case V64_SINGLE: - return FPUd.equals(category); - case QUAD: - return FPUq.equals(category); - default: - return false; - } - } - - @Override - public PlatformKind getLargestStorableKind(RegisterCategory category) { - if (category.equals(CPU)) { - return SPARCKind.XWORD; - } else if (category.equals(FPUd)) { - return SPARCKind.DOUBLE; - } else if (category.equals(FPUs)) { - return SPARCKind.SINGLE; - } else if (category.equals(FPUq)) { - return SPARCKind.QUAD; - } else { - throw new IllegalArgumentException("Unknown register category: " + category); - } - } - - @Override - public PlatformKind getPlatformKind(JavaKind javaKind) { - switch (javaKind) { - case Boolean: - case Byte: - return SPARCKind.BYTE; - case Short: - case Char: - return SPARCKind.HWORD; - case Int: - return SPARCKind.WORD; - case Long: - case Object: - return SPARCKind.XWORD; - case Float: - return SPARCKind.SINGLE; - case Double: - return SPARCKind.DOUBLE; - default: - return null; - } - } - - private static int getDoubleEncoding(int reg) { - assert reg < 64 && ((reg & 1) == 0); - return (reg & 0x1e) | ((reg & 0x20) >> 5); - } - - private static int getQuadncoding(int reg) { - assert reg < 64 && ((reg & 1) == 0); - return (reg & 0x1c) | ((reg & 0x20) >> 5); - } - - public Set getFeatures() { - return features; - } - - public boolean hasFeature(CPUFeature feature) { - return features.contains(feature); - } - - public enum CPUFeature { - // ISA determined properties: - ADI, - AES, - BLK_INIT, - CAMELLIA, - CBCOND, - CRC32C, - DES, - DICTUNP, - FMAF, - FPCMPSHL, - HPC, - IMA, - KASUMI, - MD5, - MME, - MONT, - MPMUL, - MWAIT, - PAUSE, - PAUSE_NSEC, - POPC, - RLE, - SHA1, - SHA256, - SHA3, - SHA512, - SPARC5, - SPARC5B, - SPARC6, - V9, - VAMASK, - VIS1, - VIS2, - VIS3, - VIS3B, - VIS3C, - XMONT, - XMPMUL, - // Synthesised CPU properties: - BLK_ZEROING, - FAST_BIS, - FAST_CMOVE, - FAST_IDIV, - FAST_IND_BR, - FAST_LD, - FAST_RDPC - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARCKind.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARCKind.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARCKind.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015, 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 jdk.vm.ci.sparc; - -import jdk.vm.ci.meta.PlatformKind; - -public enum SPARCKind implements PlatformKind { - BYTE(1), - HWORD(2), - WORD(4), - XWORD(8), - SINGLE(4), - DOUBLE(8), - QUAD(16), - - V32_BYTE(4, BYTE), - V32_HWORD(4, HWORD), - - V64_BYTE(8, BYTE), - V64_HWORD(8, HWORD), - V64_WORD(8, WORD), - V64_SINGLE(8, SINGLE); - - private final int size; - private final int vectorLength; - - private final SPARCKind scalar; - private final EnumKey key = new EnumKey<>(this); - - SPARCKind(int size) { - this.size = size; - this.scalar = this; - this.vectorLength = 1; - } - - SPARCKind(int size, SPARCKind scalar) { - this.size = size; - this.scalar = scalar; - - assert size % scalar.size == 0; - this.vectorLength = size / scalar.size; - } - - public SPARCKind getScalar() { - return scalar; - } - - @Override - public int getSizeInBytes() { - return size; - } - - public int getSizeInBits() { - return getSizeInBytes() * 8; - } - - @Override - public int getVectorLength() { - return vectorLength; - } - - @Override - public Key getKey() { - return key; - } - - public boolean isInteger() { - switch (this) { - case BYTE: - case HWORD: - case WORD: - case XWORD: - return true; - default: - return false; - } - } - - public boolean isFloat() { - return !isInteger(); - } - - @Override - public char getTypeChar() { - switch (this) { - case BYTE: - return 'b'; - case HWORD: - return 'h'; - case WORD: - return 'w'; - case XWORD: - return 'd'; - case SINGLE: - return 'S'; - case DOUBLE: - case V64_BYTE: - case V64_HWORD: - case V64_WORD: - return 'D'; - default: - return '-'; - } - } -} diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/package-info.java deleted file mode 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/package-info.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2018, 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 SPARC platform independent portions of the JVMCI API. - */ -package jdk.vm.ci.sparc; diff --git a/src/jdk.internal.vm.ci/share/classes/module-info.java b/src/jdk.internal.vm.ci/share/classes/module-info.java --- a/src/jdk.internal.vm.ci/share/classes/module-info.java +++ b/src/jdk.internal.vm.ci/share/classes/module-info.java @@ -39,6 +39,5 @@ provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory, - jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory, - jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory; + jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/BitSpecTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2016, 2018, 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 org.graalvm.compiler.asm.sparc.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler.BitSpec; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CompositeBitSpec; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.ContinousBitSpec; - -public class BitSpecTest { - - private static final BitSpec d4hi = new ContinousBitSpec(23, 20, true, "d4hi"); - private static final BitSpec d4lo = new ContinousBitSpec(7, 4, false, "d4lo"); - private static final BitSpec d8 = new CompositeBitSpec(d4hi, d4lo); - - @Test - public void testContinousSignExtend() { - testSetGet(d4hi, 0x00700000, 0x00000007); - testSetGet(d4hi, 0x00800000, 0xFFFFFFF8); - } - - @Test - public void testContinousZeroExtend() { - testSetGet(d4lo, 0x000000F0, 0x0000000F); - testSetGet(d4lo, 0x00000070, 0x00000007); - } - - public void testSetGet(BitSpec bs, int encoded, int decoded) { - assertTrue(bs.valueFits(decoded)); - assertEquals(encoded, bs.setBits(0, decoded)); - assertEquals(decoded, bs.getBits(encoded)); - } - - @Test - public void testContinousSignExtendValueFits() { - assertFalse(d4hi.valueFits(0xf)); - assertFalse(d4hi.valueFits(0x10)); - assertFalse(d4hi.valueFits(0x17)); - } - - @Test - public void testContinousZeroExtendValueFits() { - assertFalse(d4lo.valueFits(0x10)); - } - - @Test(expected = AssertionError.class) - public void testContinousSignExtendSetFail1() { - d4hi.setBits(0, 0xf); - } - - @Test(expected = AssertionError.class) - public void testContinousSignExtendSetFail2() { - d4hi.setBits(0, 0xFFFFFFF0); - } - - @Test(expected = AssertionError.class) - public void testContinousZeroExtendSetFail1() { - d4lo.setBits(0, 0x10); - } - - @Test - public void testCompositeSignExtended() { - testSetGet(d8, 0x00f000c0, 0xfffffffc); - testSetGet(d8, 0x008000c0, 0xffffff8c); - testSetGet(d8, 0x007000c0, 0x7c); - } - - @Test(expected = AssertionError.class) - public void testCompositeSignExtendedFail1() { - d8.setBits(0, 0x00000080); - } - - @Test(expected = AssertionError.class) - public void testCompositeSignExtendedFail2() { - d8.setBits(0, 0xEFFFFF80); - } - - @Test - public void testCompositeValueFits() { - assertTrue(d8.valueFits(0xfffffffc)); - assertTrue(d8.valueFits(0xffffff8c)); - assertTrue(d8.valueFits(0x7c)); - assertFalse(d8.valueFits(0x8c)); - assertFalse(d8.valueFits(0xEFFFFF80)); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc.test/src/org/graalvm/compiler/asm/sparc/test/SPARCAssemblerTest.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2016, 2018, 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 org.graalvm.compiler.asm.sparc.test; - -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BR; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.CarryClear; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z; -import static jdk.vm.ci.sparc.SPARC.g0; - -import java.util.EnumSet; -import java.util.function.Consumer; - -import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.code.BailoutException; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.sparc.SPARC; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.ControlTransferOp; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.SPARCOp; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.test.GraalTest; - -public class SPARCAssemblerTest extends GraalTest { - private SPARCMacroAssembler masm; - - private static EnumSet computeFeatures() { - EnumSet features = EnumSet.noneOf(SPARC.CPUFeature.class); - features.add(SPARC.CPUFeature.CBCOND); - return features; - } - - private static TargetDescription createTarget() { - final int stackFrameAlignment = 16; - final int implicitNullCheckLimit = 4096; - final boolean inlineObjects = true; - Architecture arch = new SPARC(computeFeatures()); - return new TargetDescription(arch, true, stackFrameAlignment, implicitNullCheckLimit, inlineObjects); - } - - @Before - public void setup() { - TargetDescription target = createTarget(); - masm = new SPARCMacroAssembler(target); - } - - @Test - public void testPatchCbcod() { - testControlTransferOp(l -> CBCOND.emit(masm, CarryClear, false, g0, 3, l), -512, 511); - } - - @Test - public void testPatchBpcc() { - int maxDisp = 1 << 18; - testControlTransferOp(l -> BPCC.emit(masm, Xcc, Equal, ANNUL, PREDICT_NOT_TAKEN, l), -maxDisp, - maxDisp - 1); - } - - @Test - public void testPatchBpr() { - int maxDisp = 1 << 15; - testControlTransferOp(l -> BPR.emit(masm, Rc_z, ANNUL, PREDICT_NOT_TAKEN, g0, l), -maxDisp, - maxDisp - 1); - } - - @Test - public void testPatchBr() { - int maxDisp = 1 << 21; - testControlTransferOp(l -> BR.emit(masm, Equal, ANNUL, l), -maxDisp, - maxDisp - 1); - } - - @Test(expected = BailoutException.class) - public void testControlTransferInvalidDisp() { - int cbcondInstruction = 0x12f83f60; - CBCOND.setDisp(cbcondInstruction, 0x2ff); - } - - public void testControlTransferOp(Consumer

-     * | 00  |    a   | op2 |               b                         |
-     * |31 30|29    25|24 22|21                                      0|
-     * 
- */ - // @formatter:on - protected void fmt00(int a, int op2, int b) { - assert isImm(a, 5) && isImm(op2, 3) && isImm(b, 22) : String.format("a: 0x%x op2: 0x%x b: 0x%x", a, op2, b); - int word = 0; - BitSpec.op.setBits(word, 0); - BitSpec.rd.setBits(word, a); - BitSpec.op2.setBits(word, op2); - BitSpec.imm22.setBits(word, b); - emitInt(a << 25 | op2 << 22 | b); - } - - private void op3(Op3s op3, Opfs opf, Register rs1, Register rs2, Register rd) { - int b = opf.value << 5 | (rs2 == null ? 0 : rs2.encoding); - fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b); - } - - protected void op3(Op3s op3, Register rs1, Register rs2, Register rd) { - int b = rs2 == null ? 0 : rs2.encoding; - int xBit = getXBit(op3); - fmt(op3.op.value, rd.encoding, op3.value, rs1 == null ? 0 : rs1.encoding, b | xBit); - } - - protected void op3(Op3s op3, Register rs1, int simm13, Register rd) { - assert isSimm13(simm13) : simm13; - int i = 1 << 13; - int simm13WithX = simm13 | getXBit(op3); - fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, i | simm13WithX & ((1 << 13) - 1)); - } - - public void insertNopAfterCBCond() { - int pos = position() - INSTRUCTION_SIZE; - if (pos == 0) { - return; - } - int inst = getInt(pos); - if (CBCOND.match(inst)) { - nop(); - } - } - - protected int patchUnbound(Label label) { - label.addPatchAt(position(), this); - return 0; - } - - // @formatter:off - /** - * NOP. - *
-     * | 00  |00000| 100 |                0                    |
-     * |31 30|29 25|24 22|21                                  0|
-     * 
- */ - // @formatter:on - public void nop() { - emitInt(1 << 24); - } - - public void sethi(int imm22, Register dst) { - fmt00(dst.encoding, Op2s.Sethi.value, imm22); - } - - // @formatter:off - /** - * Instruction format for calls. - *
-     * | 01  |                      disp30                             |
-     * |31 30|29                                                      0|
-     * 
- * - * @return Position of the call instruction - */ - // @formatter:on - public int call(int disp30) { - assert isImm(disp30, 30); - insertNopAfterCBCond(); - int before = position(); - int instr = 1 << 30; - instr |= disp30; - emitInt(instr); - return before; - } - - public void add(Register rs1, Register rs2, Register rd) { - op3(Add, rs1, rs2, rd); - } - - public void add(Register rs1, int simm13, Register rd) { - op3(Add, rs1, simm13, rd); - } - - public void addc(Register rs1, Register rs2, Register rd) { - op3(Addc, rs1, rs2, rd); - } - - public void addc(Register rs1, int simm13, Register rd) { - op3(Addc, rs1, simm13, rd); - } - - public void addcc(Register rs1, Register rs2, Register rd) { - op3(Addcc, rs1, rs2, rd); - } - - public void addcc(Register rs1, int simm13, Register rd) { - op3(Addcc, rs1, simm13, rd); - } - - public void and(Register rs1, Register rs2, Register rd) { - op3(And, rs1, rs2, rd); - } - - public void and(Register rs1, int simm13, Register rd) { - op3(And, rs1, simm13, rd); - } - - public void andcc(Register rs1, Register rs2, Register rd) { - op3(Andcc, rs1, rs2, rd); - } - - public void andcc(Register rs1, int simm13, Register rd) { - op3(Andcc, rs1, simm13, rd); - } - - public void andn(Register rs1, Register rs2, Register rd) { - op3(Andn, rs1, rs2, rd); - } - - public void andn(Register rs1, int simm13, Register rd) { - op3(Andn, rs1, simm13, rd); - } - - public void andncc(Register rs1, Register rs2, Register rd) { - op3(Andncc, rs1, rs2, rd); - } - - public void andncc(Register rs1, int simm13, Register rd) { - op3(Andncc, rs1, simm13, rd); - } - - public void movwtos(Register rs2, Register rd) { - assert isSingleFloatRegister(rd) && isCPURegister(rs2) : String.format("%s %s", rs2, rd); - op3(Impdep1, Movwtos, null, rs2, rd); - } - - public void umulxhi(Register rs1, Register rs2, Register rd) { - op3(Impdep1, UMulxhi, rs1, rs2, rd); - } - - public void fdtos(Register rs2, Register rd) { - assert isSingleFloatRegister(rd) && isDoubleFloatRegister(rs2) : String.format("%s %s", rs2, rd); - op3(Fpop1, Fdtos, null, rs2, rd); - } - - public void movstouw(Register rs2, Register rd) { - assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd); - op3(Impdep1, Movstosw, null, rs2, rd); - } - - public void movstosw(Register rs2, Register rd) { - assert isSingleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd); - op3(Impdep1, Movstosw, null, rs2, rd); - } - - public void movdtox(Register rs2, Register rd) { - assert isDoubleFloatRegister(rs2) && isCPURegister(rd) : String.format("%s %s", rs2, rd); - op3(Impdep1, Movdtox, null, rs2, rd); - } - - public void movxtod(Register rs2, Register rd) { - assert isCPURegister(rs2) && isDoubleFloatRegister(rd) : String.format("%s %s", rs2, rd); - op3(Impdep1, Movxtod, null, rs2, rd); - } - - public void fadds(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fadds, rs1, rs2, rd); - } - - public void faddd(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Faddd, rs1, rs2, rd); - } - - public void fdivs(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fdivs, rs1, rs2, rd); - } - - public void fdivd(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fdivd, rs1, rs2, rd); - } - - public void fmovs(Register rs2, Register rd) { - op3(Fpop1, Fmovs, null, rs2, rd); - } - - public void fmovd(Register rs2, Register rd) { - op3(Fpop1, Fmovd, null, rs2, rd); - } - - public void fsrc2s(Register rs2, Register rd) { - op3(Impdep1, Fsrc2s, null, rs2, rd); - } - - public void fsrc2d(Register rs2, Register rd) { - op3(Impdep1, Fsrc2d, null, rs2, rd); - } - - public void fmuls(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fmuls, rs1, rs2, rd); - } - - public void fsmuld(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fsmuld, rs1, rs2, rd); - } - - public void fmuld(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fmuld, rs1, rs2, rd); - } - - public void fnegs(Register rs2, Register rd) { - op3(Fpop1, Fnegs, null, rs2, rd); - } - - public void fnegd(Register rs2, Register rd) { - op3(Fpop1, Fnegd, null, rs2, rd); - } - - /** - * Helper method to determine if the instruction needs the X bit set. - */ - private static int getXBit(Op3s op3) { - switch (op3) { - case Sllx: - case Srax: - case Srlx: - return 1 << 12; - default: - return 0; - } - } - - public void fstoi(Register rs2, Register rd) { - op3(Fpop1, Fstoi, null, rs2, rd); - } - - public void fstox(Register rs2, Register rd) { - op3(Fpop1, Fstox, null, rs2, rd); - } - - public void fdtox(Register rs2, Register rd) { - op3(Fpop1, Fdtox, null, rs2, rd); - } - - public void fstod(Register rs2, Register rd) { - op3(Fpop1, Fstod, null, rs2, rd); - } - - public void fdtoi(Register rs2, Register rd) { - op3(Fpop1, Fdtoi, null, rs2, rd); - } - - public void fitos(Register rs2, Register rd) { - op3(Fpop1, Fitos, null, rs2, rd); - } - - public void fitod(Register rs2, Register rd) { - op3(Fpop1, Fitod, null, rs2, rd); - } - - public void fxtos(Register rs2, Register rd) { - op3(Fpop1, Fxtos, null, rs2, rd); - } - - public void fxtod(Register rs2, Register rd) { - op3(Fpop1, Fxtod, null, rs2, rd); - } - - public void fzeros(Register rd) { - op3(Impdep1, Fzeros, null, null, rd); - } - - public void fzerod(Register rd) { - op3(Impdep1, Fzerod, null, null, rd); - } - - public void flushw() { - op3(Flushw, g0, g0, g0); - } - - public void fsqrtd(Register rs2, Register rd) { - op3(Fpop1, Fsqrtd, null, rs2, rd); - } - - public void fsqrts(Register rs2, Register rd) { - op3(Fpop1, Fsqrts, null, rs2, rd); - } - - public void fabss(Register rs2, Register rd) { - op3(Fpop1, Fabss, null, rs2, rd); - } - - public void fabsd(Register rs2, Register rd) { - op3(Fpop1, Fabsd, null, rs2, rd); - } - - public void fsubs(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fsubs, rs1, rs2, rd); - } - - public void fsubd(Register rs1, Register rs2, Register rd) { - op3(Fpop1, Fsubd, rs1, rs2, rd); - } - - // @formatter:off - /** - * Instruction format for fcmp. - *
-     * | 10  | --- |cc1|cc0|desc |   rs1   |   opf  | rs2 |
-     * |31 30|29 27|26 |25 |24 19|18     14|13     5|4   0|
-     * 
- */ - // @formatter:on - public void fcmp(CC cc, Opfs opf, Register rs1, Register rs2) { - int a = cc.value; - int b = opf.value << 5 | rs2.encoding; - delaySlotOptimizationPoints.add(position()); - fmt10(a, Fpop2.value, rs1.encoding, b); - } - - // @formatter:off - /** - * Instruction format for most arithmetic stuff. - *
-     * |  10 | rd  | op3 | rs1 |   b   |
-     * |31 30|29 25|24 19|18 14|13    0|
-     * 
- */ - // @formatter:on - protected void fmt10(int rd, int op3, int rs1, int b) { - fmt(0b10, rd, op3, rs1, b); - } - - // @formatter:off - /** - * Instruction format for most arithmetic stuff. - *
-     * |  op | rd  | op3 | rs1 |   b   |
-     * |31 30|29 25|24 19|18 14|13    0|
-     * 
- */ - // @formatter:on - protected void fmt(int op, int rd, int op3, int rs1, int b) { - assert isImm(rd, 5) && isImm(op3, 6) && isImm(b, 14) : String.format("rd: 0x%x op3: 0x%x b: 0x%x", rd, op3, b); - int instr = op << 30 | rd << 25 | op3 << 19 | rs1 << 14 | b; - emitInt(instr); - } - - public void illtrap(int const22) { - fmt00(0, Op2s.Illtrap.value, const22); - } - - public void jmpl(Register rs1, Register rs2, Register rd) { - insertNopAfterCBCond(); - op3(Jmpl, rs1, rs2, rd); - } - - /** - * @return Position of the jmpl instruction - */ - public int jmpl(Register rs1, int simm13, Register rd) { - insertNopAfterCBCond(); - int before = position(); - op3(Jmpl, rs1, simm13, rd); - return before; - } - - public void fmovdcc(ConditionFlag cond, CC cc, Register rs2, Register rd) { - fmovcc(cond, cc, rs2, rd, OpfLow.Fmovdcc.value); - } - - public void fmovscc(ConditionFlag cond, CC cc, Register rs2, Register rd) { - fmovcc(cond, cc, rs2, rd, OpfLow.Fmovscc.value); - } - - private void fmovcc(ConditionFlag cond, CC cc, Register rs2, Register rd, int opfLow) { - int opfCC = cc.getOpfCCValue(); - int a = opfCC << 11 | opfLow << 5 | rs2.encoding; - fmt10(rd.encoding, Fpop2.value, cond.value, a); - } - - public void movcc(ConditionFlag conditionFlag, CC cc, Register rs2, Register rd) { - movcc(conditionFlag, cc, 0, rs2.encoding, rd); - } - - public void movcc(ConditionFlag conditionFlag, CC cc, int simm11, Register rd) { - assert isSimm11(simm11); - movcc(conditionFlag, cc, 1, simm11 & ((1 << 11) - 1), rd); - } - - private void movcc(ConditionFlag conditionFlag, CC cc, int i, int imm, Register rd) { - int cc01 = 0b11 & cc.value; - int cc2 = cc.isFloat ? 0 : 1; - int a = cc2 << 4 | conditionFlag.value; - int b = cc01 << 11 | i << 13 | imm; - fmt10(rd.encoding, Movcc.value, a, b); - } - - public void mulx(Register rs1, Register rs2, Register rd) { - op3(Mulx, rs1, rs2, rd); - } - - public void mulx(Register rs1, int simm13, Register rd) { - op3(Mulx, rs1, simm13, rd); - } - - public void or(Register rs1, Register rs2, Register rd) { - assert isCPURegister(rs1, rs2, rd) : String.format("%s %s %s", rs1, rs2, rd); - op3(Or, rs1, rs2, rd); - } - - public void or(Register rs1, int simm13, Register rd) { - assert isCPURegister(rs1, rd) : String.format("%s %s", rs1, rd); - op3(Or, rs1, simm13, rd); - } - - public void popc(Register rs2, Register rd) { - op3(Popc, g0, rs2, rd); - } - - public void popc(int simm13, Register rd) { - op3(Popc, g0, simm13, rd); - } - - public void prefetch(SPARCAddress addr, Fcn fcn) { - Register rs1 = addr.getBase(); - if (addr.getIndex().equals(Register.None)) { - int dis = addr.getDisplacement(); - assert isSimm13(dis); - fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, 1 << 13 | dis & ((1 << 13) - 1)); - } else { - Register rs2 = addr.getIndex(); - fmt(Prefetch.op.value, fcn.value, Prefetch.value, rs1.encoding, rs2.encoding); - } - } - - // A.44 Read State Register - - public void rdpc(Register rd) { - op3(Rd, g5, g0, rd); - } - - public void restore(Register rs1, Register rs2, Register rd) { - op3(Restore, rs1, rs2, rd); - } - - public static final int PC_RETURN_OFFSET = 8; - - public void save(Register rs1, Register rs2, Register rd) { - op3(Save, rs1, rs2, rd); - } - - public void save(Register rs1, int simm13, Register rd) { - op3(Save, rs1, simm13, rd); - } - - public void sdivx(Register rs1, Register rs2, Register rd) { - op3(Sdivx, rs1, rs2, rd); - } - - public void sdivx(Register rs1, int simm13, Register rd) { - op3(Sdivx, rs1, simm13, rd); - } - - public void udivx(Register rs1, Register rs2, Register rd) { - op3(Udivx, rs1, rs2, rd); - } - - public void udivx(Register rs1, int simm13, Register rd) { - op3(Udivx, rs1, simm13, rd); - } - - public void sll(Register rs1, Register rs2, Register rd) { - op3(Sll, rs1, rs2, rd); - } - - public void sll(Register rs1, int shcnt32, Register rd) { - assert isImm(shcnt32, 5); - op3(Sll, rs1, shcnt32, rd); - } - - public void sllx(Register rs1, Register rs2, Register rd) { - op3(Sllx, rs1, rs2, rd); - } - - public void sllx(Register rs1, int shcnt64, Register rd) { - assert isImm(shcnt64, 6); - op3(Sllx, rs1, shcnt64, rd); - } - - public void sra(Register rs1, Register rs2, Register rd) { - op3(Sra, rs1, rs2, rd); - } - - public void sra(Register rs1, int simm13, Register rd) { - op3(Sra, rs1, simm13, rd); - } - - public void srax(Register rs1, Register rs2, Register rd) { - op3(Srax, rs1, rs2, rd); - } - - public void srax(Register rs1, int shcnt64, Register rd) { - assert isImm(shcnt64, 6); - op3(Srax, rs1, shcnt64, rd); - } - - public void srl(Register rs1, Register rs2, Register rd) { - op3(Srl, rs1, rs2, rd); - } - - public void srl(Register rs1, int simm13, Register rd) { - op3(Srl, rs1, simm13, rd); - } - - public void srlx(Register rs1, Register rs2, Register rd) { - op3(Srlx, rs1, rs2, rd); - } - - public void srlx(Register rs1, int shcnt64, Register rd) { - assert isImm(shcnt64, 6); - op3(Srlx, rs1, shcnt64, rd); - } - - public void sub(Register rs1, Register rs2, Register rd) { - op3(Sub, rs1, rs2, rd); - } - - public void sub(Register rs1, int simm13, Register rd) { - op3(Sub, rs1, simm13, rd); - } - - public void subcc(Register rs1, Register rs2, Register rd) { - op3(Subcc, rs1, rs2, rd); - } - - public void subcc(Register rs1, int simm13, Register rd) { - op3(Subcc, rs1, simm13, rd); - } - - public void ta(int trap) { - tcc(Icc, Always, trap); - } - - public void pause() { - // Maybe fmt10(rd=0b1_1011, op3=0b11_0000, rs1=0, i=1, simm13=1), or - // maybe op3(Wr, g0, 1, %pause). - // What should the count be? - GraalError.unimplemented("The SPARC pause instruction is not yet implemented."); - } - - public void tcc(CC cc, ConditionFlag flag, int trap) { - assert isImm(trap, 8); - int b = cc.value << 11; - b |= 1 << 13; - b |= trap; - fmt10(flag.value, Op3s.Tcc.getValue(), 0, b); - } - - public void wrccr(Register rs1, Register rs2) { - op3(Wr, rs1, rs2, g2); - } - - public void wrccr(Register rs1, int simm13) { - op3(Wr, rs1, simm13, g2); - } - - public void xor(Register rs1, Register rs2, Register rd) { - op3(Xor, rs1, rs2, rd); - } - - public void xor(Register rs1, int simm13, Register rd) { - op3(Xor, rs1, simm13, rd); - } - - public void xorcc(Register rs1, Register rs2, Register rd) { - op3(Xorcc, rs1, rs2, rd); - } - - public void xorcc(Register rs1, int simm13, Register rd) { - op3(Xorcc, rs1, simm13, rd); - } - - public void xnor(Register rs1, Register rs2, Register rd) { - op3(Xnor, rs1, rs2, rd); - } - - public void xnor(Register rs1, int simm13, Register rd) { - op3(Xnor, rs1, simm13, rd); - } - - /* - * Load/Store - */ - protected void ld(Op3s op3, SPARCAddress addr, Register rd, Asi asi) { - Register rs1 = addr.getBase(); - if (!addr.getIndex().equals(Register.None)) { - Register rs2 = addr.getIndex(); - if (asi != null) { - int b = rs2.encoding; - b |= asi.value << 5; - fmt(op3.op.value, rd.encoding, op3.value, rs1.encoding, b); - } else { - op3(op3, rs1, rs2, rd); - } - } else { - int imm = addr.getDisplacement(); - op3(op3, rs1, imm, rd); - } - } - - protected void ld(Op3s op3, SPARCAddress addr, Register rd) { - ld(op3, addr, rd, null); - } - - public void lddf(SPARCAddress src, Register dst) { - assert isDoubleFloatRegister(dst) : dst; - ld(Lddf, src, dst); - } - - public void ldf(SPARCAddress src, Register dst) { - assert isSingleFloatRegister(dst) : dst; - ld(Ldf, src, dst); - } - - public void lduh(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Lduh, src, dst); - } - - public void ldsh(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Ldsh, src, dst); - } - - public void ld(SPARCAddress src, Register dst, int bytes, boolean signExtend) { - if (isCPURegister(dst)) { - if (signExtend) { - switch (bytes) { - case 1: - ld(Ldsb, src, dst); - break; - case 2: - ld(Ldsh, src, dst); - break; - case 4: - ld(Ldsw, src, dst); - break; - case 8: - ld(Ldx, src, dst); - break; - default: - throw new InternalError(); - } - } else { - switch (bytes) { - case 1: - ld(Ldub, src, dst); - break; - case 2: - ld(Lduh, src, dst); - break; - case 4: - ld(Lduw, src, dst); - break; - case 8: - ld(Ldx, src, dst); - break; - default: - throw new InternalError(); - } - } - } else if (isDoubleFloatRegister(dst) && bytes == 8) { - assert !signExtend; - ld(Lddf, src, dst); - } else if (isSingleFloatRegister(dst) && bytes == 4) { - assert !signExtend; - ld(Ldf, src, dst); - } else { - throw new InternalError(String.format("src: %s dst: %s bytes: %d signExtend: %b", src, dst, bytes, signExtend)); - } - } - - public void st(Register src, SPARCAddress dst, int bytes) { - if (isCPURegister(src)) { - switch (bytes) { - case 1: - st(Stb, src, dst); - break; - case 2: - st(Sth, src, dst); - break; - case 4: - st(Stw, src, dst); - break; - case 8: - st(Stx, src, dst); - break; - default: - throw new InternalError(Integer.toString(bytes)); - } - } else if (isDoubleFloatRegister(src) && bytes == 8) { - st(Stdf, src, dst); - } else if (isSingleFloatRegister(src) && bytes == 4) { - st(Stf, src, dst); - } else { - throw new InternalError(String.format("src: %s dst: %s bytes: %d", src, dst, bytes)); - } - } - - public void ldub(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Ldub, src, dst); - } - - public void ldsb(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Ldsb, src, dst); - } - - public void lduw(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Lduw, src, dst); - } - - public void ldsw(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Ldsw, src, dst); - } - - public void ldx(SPARCAddress src, Register dst) { - assert isCPURegister(dst) : dst; - ld(Ldx, src, dst); - } - - public void ldxa(Register rs1, Register rs2, Register rd, Asi asi) { - assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd); - ld(Ldxa, new SPARCAddress(rs1, rs2), rd, asi); - } - - public void lduwa(Register rs1, Register rs2, Register rd, Asi asi) { - assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd); - ld(Lduwa, new SPARCAddress(rs1, rs2), rd, asi); - } - - public void stxa(Register rd, Register rs1, Register rs2, Asi asi) { - assert isCPURegister(rs1, rs2, rd) : format("%s %s %s", rs1, rs2, rd); - ld(Stxa, new SPARCAddress(rs1, rs2), rd, asi); - } - - protected void st(Op3s op3, Register rs1, SPARCAddress dest) { - ld(op3, dest, rs1); - } - - public void stdf(Register rd, SPARCAddress addr) { - assert isDoubleFloatRegister(rd) : rd; - st(Stdf, rd, addr); - } - - public void stf(Register rd, SPARCAddress addr) { - assert isSingleFloatRegister(rd) : rd; - st(Stf, rd, addr); - } - - public void stb(Register rd, SPARCAddress addr) { - assert isCPURegister(rd) : rd; - st(Stb, rd, addr); - } - - public void sth(Register rd, SPARCAddress addr) { - assert isCPURegister(rd) : rd; - st(Sth, rd, addr); - } - - public void stw(Register rd, SPARCAddress addr) { - assert isCPURegister(rd) : rd; - st(Stw, rd, addr); - } - - public void stx(Register rd, SPARCAddress addr) { - assert isCPURegister(rd) : rd; - st(Stx, rd, addr); - } - - public void membar(int barriers) { - op3(Membar, o7, barriers, g0); - } - - public void casa(Register rs1, Register rs2, Register rd, Asi asi) { - ld(Casa, new SPARCAddress(rs1, rs2), rd, asi); - } - - public void casxa(Register rs1, Register rs2, Register rd, Asi asi) { - ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi); - } - - @Override - public InstructionCounter getInstructionCounter() { - return new SPARCInstructionCounter(this); - } - - public void patchAddImmediate(int position, int simm13) { - int inst = getInt(position); - assert SPARCAssembler.isSimm13(simm13) : simm13; - assert (inst >>> 30) == 0b10 : String.format("0x%x", inst); - assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst); - assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst); - inst = inst & (~((1 << 13) - 1)); - inst |= simm13 & ((1 << 12) - 1); - emitInt(inst, position); - } - - public void fpadd32(Register rs1, Register rs2, Register rd) { - op3(Impdep1, Fpadd32, rs1, rs2, rd); - } - - /** - * Does peephole optimization on code generated by this assembler. This method should be called - * at the end of code generation. - *

- * It searches for conditional branch instructions which has nop in the delay slot then looks at - * the instruction at branch target; if it is an arithmetic instruction, which does not throw an - * exception (e.g. division), it pulls this instruction into the delay slot and increments the - * displacement by 1. - */ - public void peephole() { - for (int i : delaySlotOptimizationPoints) { - optimizeDelaySlot(i); - } - } - - /** - * Optimizes branch instruction b which has a nop in the delay slot. It tries to stuff - * the instruction at bs branch target into the delay slot of b, set the annul - * flag and increments bs disp field by 1; - *

- * If bs branch target instruction is an unconditional branch t, then it tries to - * put ts delayed instruction into the delay slot of b and add the ts disp - * field to bs disp field. - */ - private void optimizeDelaySlot(int i) { - int delaySlotAbsolute = i + INSTRUCTION_SIZE; - int nextInst = getInt(delaySlotAbsolute); - SPARCOp nextOp = getSPARCOp(nextInst); - if (nextOp instanceof Sethi && Sethi.isNop(nextInst)) { - int inst = getInt(i); - SPARCOp op = getSPARCOp(inst); - if (op instanceof ControlTransferOp && ((ControlTransferOp) op).hasDelaySlot() && ((ControlTransferOp) op).isAnnulable(inst)) { - ControlTransferOp ctOp = (ControlTransferOp) op; - int disp = ctOp.getDisp(inst); - int branchTargetAbsolute = i + disp * INSTRUCTION_SIZE; - int branchTargetInst = getInt(branchTargetAbsolute); - SPARCOp branchTargetOp = getSPARCOp(branchTargetInst); - if (branchTargetOp instanceof Op3Op) { - Op3s op3 = ((Op3Op) branchTargetOp).getOp3(branchTargetInst); - if (!op3.throwsException()) { - inst = ctOp.setDisp(inst, disp + 1); // Increment the offset - inst = ctOp.setAnnul(inst, true); - emitInt(inst, i); - emitInt(branchTargetInst, delaySlotAbsolute); - } - } else if (branchTargetOp instanceof ControlTransferOp && !((ControlTransferOp) branchTargetOp).isConditional(branchTargetInst)) { - // If branchtarget is a unconditional branch - ControlTransferOp branchTargetOpBranch = (ControlTransferOp) branchTargetOp; - int btDisp = branchTargetOpBranch.getDisp(branchTargetInst); - int newDisp = disp + btDisp; - if (ctOp.isValidDisp(newDisp)) { // Test if we don't exceed field size - int instAfter = ctOp.setDisp(inst, newDisp); - instAfter = ctOp.setAnnul(instAfter, true); - branchTargetInst = getInt(branchTargetAbsolute + INSTRUCTION_SIZE); - branchTargetOp = getSPARCOp(branchTargetInst); - if (branchTargetOp instanceof Op3Op && !((Op3Op) branchTargetOp).getOp3(branchTargetInst).throwsException()) { - emitInt(instAfter, i); - emitInt(branchTargetInst, delaySlotAbsolute); - } - } - } - } - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCInstructionCounter.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2009, 2018, 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 org.graalvm.compiler.asm.sparc; - -import java.util.TreeMap; - -import org.graalvm.compiler.asm.Assembler.InstructionCounter; - -public class SPARCInstructionCounter implements InstructionCounter { - // Use a treemap to keep the order in the output - private static final TreeMap INSTRUCTION_MATCHER = new TreeMap<>(); - - static { - // @formatter:off - INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000)); - INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf)); - INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd)); - INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0)); - // @formatter:on - } - - private final SPARCAssembler asm; - - public SPARCInstructionCounter(SPARCAssembler asm) { - super(); - this.asm = asm; - } - - @Override - public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) { - SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length]; - for (int i = 0; i < instructionTypes.length; i++) { - String typeName = instructionTypes[i]; - matchers[i] = INSTRUCTION_MATCHER.get(typeName); - if (matchers[i] == null) { - throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet())); - } - } - return countBetween(matchers, beginPc, endPc); - } - - private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) { - int[] counts = new int[matchers.length]; - for (int p = startPc; p < endPc; p += 4) { - int instr = asm.getInt(p); - for (int i = 0; i < matchers.length; i++) { - SPARCInstructionMatch matcher = matchers[i]; - if (matcher.matches(instr)) { - counts[i]++; - } - } - } - return counts; - } - - @Override - public String[] getSupportedInstructionTypes() { - return INSTRUCTION_MATCHER.keySet().toArray(new String[0]); - } - - /** - * Tests the lower 3 bits of the op3 field. - */ - private static class OP3LowBitsMatcher extends SPARCInstructionMatch { - private final int[] op3b03; - private final int op; - - OP3LowBitsMatcher(int op, int... op3b03) { - super(0, 0); - this.op = op; - this.op3b03 = op3b03; - } - - @Override - public boolean matches(int instruction) { - if (instruction >>> 30 != op) { - return false; - } - int op3lo = (instruction >> 19) & ((1 << 4) - 1); - for (int op3Part : op3b03) { - if (op3Part == op3lo) { - return true; - } - } - return false; - } - } - - private static class SPARCInstructionMatch { - private final int mask; - private final int[] patterns; - - SPARCInstructionMatch(int mask, int... patterns) { - super(); - this.mask = mask; - this.patterns = patterns; - } - - public boolean matches(int instruction) { - for (int pattern : patterns) { - if ((instruction & mask) == pattern) { - return true; - } - } - return false; - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCMacroAssembler.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.asm.sparc; - -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARC.g3; -import static jdk.vm.ci.sparc.SPARC.i7; -import static jdk.vm.ci.sparc.SPARC.o7; - -import org.graalvm.compiler.asm.AbstractAddress; -import org.graalvm.compiler.asm.Label; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.sparc.SPARC.CPUFeature; - -public class SPARCMacroAssembler extends SPARCAssembler { - - /** - * A sentinel value used as a place holder in an instruction stream for an address that will be - * patched. - */ - private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0); - private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g3), new ScratchRegister(o7)}; - // Points to the next free scratch register - private int nextFreeScratchRegister = 0; - /** - * Use ld [reg+simm13], reg for loading constants (User has to make sure, that the size of the - * constant table does not exceed simm13). - */ - private boolean immediateConstantLoad; - - public SPARCMacroAssembler(TargetDescription target) { - super(target); - } - - /** - * @see #immediateConstantLoad - */ - public void setImmediateConstantLoad(boolean immediateConstantLoad) { - this.immediateConstantLoad = immediateConstantLoad; - } - - @Override - public void align(int modulus) { - while (position() % modulus != 0) { - nop(); - } - } - - @Override - public void jmp(Label l) { - BPCC.emit(this, Xcc, Always, NOT_ANNUL, PREDICT_NOT_TAKEN, l); - nop(); // delay slot - } - - public void bz(Label l) { - BPCC.emit(this, Xcc, ConditionFlag.Zero, NOT_ANNUL, PREDICT_NOT_TAKEN, l); - } - - @Override - protected final void patchJumpTarget(int branch, int branchTarget) { - final int disp = (branchTarget - branch) / 4; - final int inst = getInt(branch); - ControlTransferOp op = (ControlTransferOp) getSPARCOp(inst); - int newInst = op.setDisp(inst, disp); - emitInt(newInst, branch); - } - - @Override - public AbstractAddress makeAddress(Register base, int displacement) { - return new SPARCAddress(base, displacement); - } - - @Override - public AbstractAddress getPlaceholder(int instructionStartPosition) { - return Placeholder; - } - - @Override - public final void ensureUniquePC() { - nop(); - } - - public void cas(Register rs1, Register rs2, Register rd) { - casa(rs1, rs2, rd, Asi.ASI_PRIMARY); - } - - public void casx(Register rs1, Register rs2, Register rd) { - casxa(rs1, rs2, rd, Asi.ASI_PRIMARY); - } - - public void clr(Register dst) { - or(g0, g0, dst); - } - - public void clrb(SPARCAddress addr) { - stb(g0, addr); - } - - public void clrh(SPARCAddress addr) { - sth(g0, addr); - } - - public void clrx(SPARCAddress addr) { - stx(g0, addr); - } - - public void cmp(Register rs1, Register rs2) { - subcc(rs1, rs2, g0); - } - - public void cmp(Register rs1, int simm13) { - subcc(rs1, simm13, g0); - } - - public void dec(Register rd) { - sub(rd, 1, rd); - } - - public void dec(int simm13, Register rd) { - sub(rd, simm13, rd); - } - - public void jmp(SPARCAddress address) { - jmpl(address.getBase(), address.getDisplacement(), g0); - } - - public void jmp(Register rd) { - jmpl(rd, 0, g0); - } - - public void neg(Register rs1, Register rd) { - sub(g0, rs1, rd); - } - - public void neg(Register rd) { - sub(g0, rd, rd); - } - - public void mov(Register rs, Register rd) { - or(g0, rs, rd); - } - - public void mov(int simm13, Register rd) { - or(g0, simm13, rd); - } - - public void not(Register rs1, Register rd) { - xnor(rs1, g0, rd); - } - - public void not(Register rd) { - xnor(rd, g0, rd); - } - - public void restoreWindow() { - restore(g0, g0, g0); - } - - public void ret() { - jmpl(i7, 8, g0); - } - - /** - * Generates sethi hi22(value), dst; or dst, lo10(value), dst; code. - */ - public void setw(int value, Register dst, boolean forceRelocatable) { - if (!forceRelocatable && isSimm13(value)) { - or(g0, value, dst); - } else { - sethi(hi22(value), dst); - or(dst, lo10(value), dst); - } - } - - public void setx(long value, Register dst, boolean forceRelocatable) { - int lo = (int) (value & ~0); - sethix(value, dst, forceRelocatable); - if (lo10(lo) != 0 || forceRelocatable) { - add(dst, lo10(lo), dst); - } - } - - public void sethix(long value, Register dst, boolean forceRelocatable) { - final int hi = (int) (value >> 32); - final int lo = (int) (value & ~0); - - // This is the same logic as MacroAssembler::internal_set. - final int startPc = position(); - if (hi == 0 && lo >= 0) { - sethi(hi22(lo), dst); - } else if (hi == -1) { - sethi(hi22(~lo), dst); - xor(dst, ~lo10(~0), dst); - } else { - final int shiftcnt; - final int shiftcnt2; - sethi(hi22(hi), dst); - if ((hi & 0x3ff) != 0) { // Any bits? - // msb 32-bits are now in lsb 32 - or(dst, hi & 0x3ff, dst); - } - if ((lo & 0xFFFFFC00) != 0) { // done? - if (((lo >> 20) & 0xfff) != 0) { // Any bits set? - // Make room for next 12 bits - sllx(dst, 12, dst); - // Or in next 12 - or(dst, (lo >> 20) & 0xfff, dst); - shiftcnt = 0; // We already shifted - } else { - shiftcnt = 12; - } - if (((lo >> 10) & 0x3ff) != 0) { - // Make room for last 10 bits - sllx(dst, shiftcnt + 10, dst); - // Or in next 10 - or(dst, (lo >> 10) & 0x3ff, dst); - shiftcnt2 = 0; - } else { - shiftcnt2 = 10; - } - // Shift leaving disp field 0'd - sllx(dst, shiftcnt2 + 10, dst); - } else { - sllx(dst, 32, dst); - } - } - // Pad out the instruction sequence so it can be patched later. - if (forceRelocatable) { - while (position() < (startPc + (INSTRUCTION_SIZE * 7))) { - nop(); - } - } - } - - public void signx(Register rs, Register rd) { - sra(rs, g0, rd); - } - - public void signx(Register rd) { - sra(rd, g0, rd); - } - - public boolean isImmediateConstantLoad() { - return immediateConstantLoad; - } - - public ScratchRegister getScratchRegister() { - return scratchRegister[nextFreeScratchRegister++]; - } - - public class ScratchRegister implements AutoCloseable { - private final Register register; - - public ScratchRegister(Register register) { - super(); - this.register = register; - } - - public Register getRegister() { - return register; - } - - @Override - public void close() { - assert nextFreeScratchRegister > 0 : "Close called too often"; - nextFreeScratchRegister--; - } - } - - public void compareBranch(Register rs1, Register rs2, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) { - assert isCPURegister(rs1, rs2); - assert ccRegister == Icc || ccRegister == Xcc; - if (hasFeature(CPUFeature.CBCOND)) { - if (delaySlotInstruction != null) { - delaySlotInstruction.run(); - } - CBCOND.emit(this, cond, ccRegister == Xcc, rs1, rs2, label); - } else { - if (cond == Equal && rs1.equals(g0)) { - BPR.emit(this, Rc_z, NOT_ANNUL, predict, rs1, label); - } else { - cmp(rs1, rs2); - BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label); - } - if (delaySlotInstruction != null) { - int positionBefore = position(); - delaySlotInstruction.run(); - int positionAfter = position(); - assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot"; - } else { - nop(); - } - } - } - - public void compareBranch(Register rs1, int simm, ConditionFlag cond, CC ccRegister, Label label, BranchPredict predict, Runnable delaySlotInstruction) { - assert isCPURegister(rs1); - assert ccRegister == Icc || ccRegister == Xcc; - if (hasFeature(CPUFeature.CBCOND)) { - if (delaySlotInstruction != null) { - delaySlotInstruction.run(); - } - CBCOND.emit(this, cond, ccRegister == Xcc, rs1, simm, label); - } else { - if (cond == Equal && simm == 0) { - BPR.emit(this, Rc_z, NOT_ANNUL, PREDICT_NOT_TAKEN, rs1, label); - } else { - cmp(rs1, simm); - BPCC.emit(this, ccRegister, cond, NOT_ANNUL, predict, label); - } - if (delaySlotInstruction != null) { - int positionBefore = position(); - delaySlotInstruction.run(); - int positionAfter = position(); - assert positionBefore - positionAfter > INSTRUCTION_SIZE : "Emitted more than one instruction into delay slot"; - } else { - nop(); - } - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCAddressLowering.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.AddNode; -import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering; - -import jdk.vm.ci.meta.JavaConstant; - -public class SPARCAddressLowering extends AddressLowering { - - @Override - public AddressNode lower(ValueNode base, ValueNode offset) { - JavaConstant immBase = asImmediate(base); - if (immBase != null && SPARCAssembler.isSimm13(immBase)) { - return lower(offset, immBase.asLong()); - } - - JavaConstant immOffset = asImmediate(offset); - if (immOffset != null && SPARCAssembler.isSimm13(immOffset)) { - return lower(base, immOffset.asLong()); - } - return base.graph().unique(new SPARCIndexedAddressNode(base, offset)); - } - - private AddressNode lower(ValueNode base, long displacement) { - if (base instanceof AddNode) { - AddNode add = (AddNode) base; - - JavaConstant immX = asImmediate(add.getX()); - if (immX != null && SPARCAssembler.isSimm13(displacement + immX.asLong())) { - return lower(add.getY(), displacement + immX.asLong()); - } - - JavaConstant immY = asImmediate(add.getY()); - if (immY != null && SPARCAssembler.isSimm13(displacement + immY.asLong())) { - return lower(add.getX(), displacement + immY.asLong()); - } - - if (displacement == 0) { - return lower(add.getX(), add.getY()); - } - } - - assert SPARCAssembler.isSimm13(displacement); - return base.graph().unique(new SPARCImmediateAddressNode(base, (int) displacement)); - } - - private static JavaConstant asImmediate(ValueNode value) { - JavaConstant c = value.asJavaConstant(); - if (c != null && c.getJavaKind().isNumericInteger()) { - return c; - } else { - return null; - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Copyright (c) 2009, 2019, 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 org.graalvm.compiler.core.sparc; - -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Add; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Addcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.And; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Mulx; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sdivx; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sllx; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sra; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srax; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Srl; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Sub; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Udivx; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Xnor; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Faddd; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fadds; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fdtos; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitod; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fitos; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuld; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fmuls; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegd; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fnegs; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fstod; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fxtod; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.UMulxhi; -import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_DREM; -import static org.graalvm.compiler.core.target.Backend.ARITHMETIC_FREM; -import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.BSF; -import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.IBSR; -import static org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp.IntrinsicOpcode.LBSR; -import static jdk.vm.ci.code.CodeUtil.mask; -import static jdk.vm.ci.meta.JavaConstant.forLong; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; -import static jdk.vm.ci.sparc.SPARCKind.SINGLE; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.calc.FloatConvert; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.ConstantValue; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.Variable; -import org.graalvm.compiler.lir.VirtualStackSlot; -import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; -import org.graalvm.compiler.lir.sparc.SPARCAddressValue; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.FloatConvertOp; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.MulHighOp.MulHigh; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.RemOp.Rem; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCIMulccOp; -import org.graalvm.compiler.lir.sparc.SPARCArithmetic.SPARCLMulccOp; -import org.graalvm.compiler.lir.sparc.SPARCBitManipulationOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.MoveFpGp; -import org.graalvm.compiler.lir.sparc.SPARCMove.StoreConstantOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp; -import org.graalvm.compiler.lir.sparc.SPARCOP3Op; -import org.graalvm.compiler.lir.sparc.SPARCOPFOp; - -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.meta.ValueKind; -import jdk.vm.ci.sparc.SPARC; -import jdk.vm.ci.sparc.SPARC.CPUFeature; -import jdk.vm.ci.sparc.SPARCKind; - -/** - * This class implements the SPARC specific portion of the LIR generator. - */ -public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator { - - @Override - public SPARCLIRGenerator getLIRGen() { - return (SPARCLIRGenerator) super.getLIRGen(); - } - - @Override - public Variable emitBitCount(Value operand) { - Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); - AllocatableValue usedOperand = asAllocatable(emitZeroExtend(operand)); - getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result)); - return result; - } - - @Override - public Variable emitBitScanForward(Value operand) { - Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); - getLIRGen().append(new SPARCBitManipulationOp(BSF, result, asAllocatable(operand), getLIRGen())); - return result; - } - - @Override - public Variable emitBitScanReverse(Value operand) { - Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD)); - if (operand.getPlatformKind() == SPARCKind.XWORD) { - getLIRGen().append(new SPARCBitManipulationOp(LBSR, result, asAllocatable(operand), getLIRGen())); - } else { - getLIRGen().append(new SPARCBitManipulationOp(IBSR, result, asAllocatable(operand), getLIRGen())); - } - return result; - } - - @Override - public Value emitMathAbs(Value inputValue) { - Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); - SPARCKind kind = (SPARCKind) inputValue.getPlatformKind(); - Opfs opf; - switch (kind) { - case SINGLE: - opf = Opfs.Fabss; - break; - case DOUBLE: - opf = Opfs.Fabsd; - break; - default: - throw GraalError.shouldNotReachHere("Input kind: " + kind); - } - getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result)); - return result; - } - - @Override - public Value emitMathSqrt(Value inputValue) { - Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); - SPARCKind kind = (SPARCKind) inputValue.getPlatformKind(); - Opfs opf; - switch (kind) { - case SINGLE: - opf = Opfs.Fsqrts; - break; - case DOUBLE: - opf = Opfs.Fsqrtd; - break; - default: - throw GraalError.shouldNotReachHere("Input kind: " + kind); - } - getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result)); - return result; - } - - @Override - public Value emitNegate(Value input) { - PlatformKind inputKind = input.getPlatformKind(); - if (isNumericInteger(inputKind)) { - return emitUnary(Sub, input); - } else { - return emitUnary(inputKind.equals(DOUBLE) ? Fnegd : Fnegs, input); - } - } - - @Override - public Value emitNot(Value input) { - return emitUnary(Xnor, input); - } - - private Variable emitUnary(Opfs opf, Value inputValue) { - Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue)); - getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), asAllocatable(inputValue), result)); - return result; - } - - private Variable emitUnary(Op3s op3, Value input) { - Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - getLIRGen().append(SPARCOP3Op.newUnary(op3, getLIRGen().loadSimm13(input), result)); - return result; - } - - private Variable emitBinary(ValueKind resultKind, Opfs opf, Value a, Value b) { - return emitBinary(resultKind, opf, a, b, null); - } - - private Variable emitBinary(ValueKind resultKind, Opfs opf, Value a, Value b, LIRFrameState state) { - Variable result = getLIRGen().newVariable(resultKind); - getLIRGen().append(new SPARCOPFOp(opf, asAllocatable(a), asAllocatable(b), result, state)); - return result; - } - - private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, int b) { - return emitBinary(resultKind, op3, a, new ConstantValue(LIRKind.value(WORD), JavaConstant.forInt(b))); - } - - private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, Value b) { - return emitBinary(resultKind, op3, a, b, null); - } - - private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, Value b, LIRFrameState state) { - Variable result = getLIRGen().newVariable(resultKind); - if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) { - getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), getLIRGen().loadSimm13(a), result, state)); - } else { - getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), getLIRGen().loadSimm13(b), result, state)); - } - return result; - } - - @Override - protected boolean isNumericInteger(PlatformKind kind) { - return ((SPARCKind) kind).isInteger(); - } - - @Override - public Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags) { - if (isNumericInteger(a.getPlatformKind())) { - return emitBinary(resultKind, setFlags ? Addcc : Add, a, b); - } else { - boolean isDouble = a.getPlatformKind().equals(DOUBLE); - return emitBinary(resultKind, isDouble ? Faddd : Fadds, a, b); - } - } - - @Override - public Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags) { - if (isNumericInteger(a.getPlatformKind())) { - return emitBinary(resultKind, setFlags ? Subcc : Sub, a, b); - } else { - boolean isDouble = a.getPlatformKind().equals(DOUBLE); - return emitBinary(resultKind, isDouble ? Opfs.Fsubd : Opfs.Fsubs, a, b); - } - } - - @Override - public Variable emitMul(Value a, Value b, boolean setFlags) { - LIRKind resultKind = LIRKind.combine(a, b); - PlatformKind aKind = a.getPlatformKind(); - if (isNumericInteger(aKind)) { - if (setFlags) { - Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); - if (aKind == XWORD) { - getLIRGen().append(new SPARCLMulccOp(result, getLIRGen().load(a), getLIRGen().load(b), getLIRGen())); - } else if (aKind == WORD) { - getLIRGen().append(new SPARCIMulccOp(result, getLIRGen().load(a), getLIRGen().load(b))); - } else { - throw GraalError.shouldNotReachHere(); - } - return result; - } else { - return emitBinary(resultKind, Op3s.Mulx, a, b); - } - } else { - boolean isDouble = a.getPlatformKind().equals(DOUBLE); - return emitBinary(resultKind, isDouble ? Fmuld : Fmuls, a, b); - } - } - - @Override - public Value emitMulHigh(Value a, Value b) { - MulHigh opcode; - switch (((SPARCKind) a.getPlatformKind())) { - case WORD: - opcode = MulHigh.IMUL; - break; - case XWORD: - opcode = MulHigh.LMUL; - break; - default: - throw GraalError.shouldNotReachHere(); - } - return emitMulHigh(opcode, a, b); - } - - @Override - public Value emitUMulHigh(Value a, Value b) { - switch (((SPARCKind) a.getPlatformKind())) { - case WORD: - Value result = emitBinary(LIRKind.combine(a, b), Mulx, emitZeroExtend(a), emitZeroExtend(b)); - return emitBinary(LIRKind.combine(a, b), Srax, result, WORD.getSizeInBits()); - case XWORD: - return emitBinary(LIRKind.combine(a, b), UMulxhi, a, b); - default: - throw GraalError.shouldNotReachHere(); - } - } - - private Value emitMulHigh(MulHigh opcode, Value a, Value b) { - Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); - MulHighOp mulHigh = new MulHighOp(opcode, getLIRGen().load(a), getLIRGen().load(b), result, getLIRGen().newVariable(LIRKind.combine(a, b))); - getLIRGen().append(mulHigh); - return result; - } - - @Override - public Value emitDiv(Value a, Value b, LIRFrameState state) { - LIRKind resultKind = LIRKind.combine(a, b); - if (isJavaConstant(b) && asJavaConstant(b).isDefaultForKind()) { // Div by zero - Value zero = SPARC.g0.asValue(LIRKind.value(SPARCKind.WORD)); - return emitBinary(resultKind, Op3s.Sdivx, zero, zero, state); - } else if (isNumericInteger(a.getPlatformKind())) { - return emitBinary(resultKind, Op3s.Sdivx, emitSignExtend(a), emitSignExtend(b), state); - } else { - boolean isDouble = a.getPlatformKind() == DOUBLE; - return emitBinary(resultKind, isDouble ? Opfs.Fdivd : Opfs.Fdivs, a, b, state); - } - } - - @Override - public Value emitRem(Value a, Value b, LIRFrameState state) { - Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); - Variable q1; // Intermediate values - Variable q2; - switch ((SPARCKind) a.getPlatformKind()) { - case WORD: - // Sign extend a and b - Value as = emitSignExtend(a); - Value bs = emitSignExtend(b); - q1 = emitBinary(as.getValueKind(), Sdivx, as, bs, state); - q2 = emitBinary(as.getValueKind(), Mulx, q1, bs); - result = emitSub(as, q2, false); - break; - case XWORD: - q1 = emitBinary(result.getValueKind(), Sdivx, a, b, state); - q2 = emitBinary(result.getValueKind(), Mulx, q1, b); - result = emitSub(a, q2, false); - break; - case SINGLE: - ForeignCallLinkage fremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_FREM); - result = getLIRGen().emitForeignCall(fremCall, state, a, b); - break; - case DOUBLE: - ForeignCallLinkage dremCall = getLIRGen().getForeignCalls().lookupForeignCall(ARITHMETIC_DREM); - result = getLIRGen().emitForeignCall(dremCall, state, a, b); - break; - default: - throw GraalError.shouldNotReachHere("missing: " + a.getPlatformKind()); - } - return result; - } - - @Override - public Value emitURem(Value a, Value b, LIRFrameState state) { - Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); - Variable scratch1 = getLIRGen().newVariable(LIRKind.combine(a, b)); - Variable scratch2 = getLIRGen().newVariable(LIRKind.combine(a, b)); - Rem opcode; - switch (((SPARCKind) a.getPlatformKind())) { - case WORD: - opcode = Rem.IUREM; - break; - case XWORD: - opcode = Rem.LUREM; - break; - default: - throw GraalError.shouldNotReachHere(); - } - getLIRGen().append(new RemOp(opcode, result, asAllocatable(a), asAllocatable(b), scratch1, scratch2, state)); - return result; - - } - - @Override - public Value emitUDiv(Value a, Value b, LIRFrameState state) { - return emitBinary(LIRKind.combine(a, b), Udivx, emitZeroExtend(a), emitZeroExtend(b), state); - } - - @Override - public Variable emitAnd(Value a, Value b) { - LIRKind resultKind = LIRKind.combine(a, b); - return emitBinary(resultKind, Op3s.And, a, b); - } - - @Override - public Variable emitOr(Value a, Value b) { - LIRKind resultKind = LIRKind.combine(a, b); - return emitBinary(resultKind, Op3s.Or, a, b); - } - - @Override - public Variable emitXor(Value a, Value b) { - LIRKind resultKind = LIRKind.combine(a, b); - return emitBinary(resultKind, Op3s.Xor, a, b); - } - - @Override - public Variable emitShl(Value a, Value b) { - SPARCKind aKind = (SPARCKind) a.getPlatformKind(); - LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); - Op3s op; - switch (aKind) { - case WORD: - op = Op3s.Sll; - break; - case XWORD: - op = Op3s.Sllx; - break; - default: - throw GraalError.shouldNotReachHere(String.format("Unsupported kind %s", aKind)); - } - return emitBinary(resultKind, op, a, b); - } - - @Override - public Variable emitShr(Value a, Value b) { - SPARCKind aKind = (SPARCKind) a.getPlatformKind(); - LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); - Op3s op; - switch (aKind) { - case WORD: - op = Op3s.Sra; - break; - case XWORD: - op = Op3s.Srax; - break; - default: - throw GraalError.shouldNotReachHere(); - } - return emitBinary(resultKind, op, a, b); - } - - @Override - public Variable emitUShr(Value a, Value b) { - SPARCKind aKind = (SPARCKind) a.getPlatformKind(); - LIRKind resultKind = LIRKind.combine(a, b).changeType(aKind); - Op3s op; - switch (aKind) { - case WORD: - op = Op3s.Srl; - break; - case XWORD: - op = Op3s.Srlx; - break; - default: - throw GraalError.shouldNotReachHere(); - } - return emitBinary(resultKind, op, a, b); - } - - private AllocatableValue emitConvertMove(LIRKind kind, AllocatableValue input) { - Variable result = getLIRGen().newVariable(kind); - getLIRGen().emitMove(result, input); - return result; - } - - @Override - public Value emitFloatConvert(FloatConvert op, Value inputValue) { - AllocatableValue inputAllocatable = asAllocatable(inputValue); - AllocatableValue result; - switch (op) { - case D2F: - result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE)); - getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result)); - break; - case F2D: - result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE)); - getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result)); - break; - case I2F: { - AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); - result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind()); - moveBetweenFpGp(intEncodedFloatReg, inputAllocatable); - getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result)); - break; - } - case I2D: { - // Unfortunately we must do int -> float -> double because fitod has float - // and double encoding in one instruction - AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); - result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); - moveBetweenFpGp(convertedFloatReg, inputAllocatable); - getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result)); - break; - } - case L2D: { - AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); - moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable); - AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind()); - getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg)); - result = convertedDoubleReg; - break; - } - case D2I: { - AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); - getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg)); - AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); - moveBetweenFpGp(convertedIntReg, convertedFloatReg); - result = convertedIntReg; - break; - } - case F2L: { - AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); - getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg)); - AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); - moveBetweenFpGp(convertedLongReg, convertedDoubleReg); - result = convertedLongReg; - break; - } - case F2I: { - AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); - getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg)); - AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD)); - moveBetweenFpGp(convertedIntReg, convertedFloatReg); - result = convertedIntReg; - break; - } - case D2L: { - AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); - getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg)); - AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD)); - moveBetweenFpGp(convertedLongReg, convertedDoubleReg); - result = convertedLongReg; - break; - } - case L2F: { - AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE)); - result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE)); - moveBetweenFpGp(convertedDoubleReg, inputAllocatable); - getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result)); - break; - } - default: - throw GraalError.shouldNotReachHere(); - } - return result; - } - - protected VirtualStackSlot getTempSlot(LIRKind kind) { - return getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(kind); - } - - private void moveBetweenFpGp(AllocatableValue dst, AllocatableValue src) { - AllocatableValue tempSlot; - PlatformKind dstKind = dst.getPlatformKind(); - PlatformKind srcKind = src.getPlatformKind(); - if (getLIRGen().getArchitecture().getFeatures().contains(CPUFeature.VIS3) && !(srcKind == WORD && dstKind == SINGLE) && !(srcKind == SINGLE && dstKind == WORD)) { - tempSlot = AllocatableValue.ILLEGAL; - } else { - tempSlot = getTempSlot(LIRKind.value(XWORD)); - } - getLIRGen().append(new MoveFpGp(dst, src, tempSlot)); - } - - @Override - public Value emitNarrow(Value inputVal, int bits) { - if (inputVal.getPlatformKind() == XWORD && bits <= 32) { - LIRKind resultKind = LIRKind.combine(inputVal).changeType(WORD); - Variable result = getLIRGen().newVariable(resultKind); - getLIRGen().emitMove(result, inputVal); - return result; - } else { - return inputVal; - } - } - - private Value emitSignExtend(Value inputValue) { - int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8; - return emitNarrow(emitSignExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits); - } - - @Override - public Value emitSignExtend(Value inputVal, int fromBits, int toBits) { - assert fromBits <= toBits && toBits <= XWORD.getSizeInBits(); - LIRKind shiftKind = LIRKind.value(WORD); - LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD); - int shiftCount = XWORD.getSizeInBits() - fromBits; - if (fromBits == toBits) { - return inputVal; - } else if (isJavaConstant(inputVal)) { - JavaConstant javaConstant = asJavaConstant(inputVal); - long constant; - if (javaConstant.isNull()) { - constant = 0; - } else { - constant = javaConstant.asLong(); - } - return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount)); - } else { - AllocatableValue inputAllocatable = asAllocatable(inputVal); - Variable result = getLIRGen().newVariable(resultKind); - if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) { - getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result)); - } else { - Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD)); - getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp)); - getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result)); - } - return result; - } - } - - private Value emitZeroExtend(Value inputValue) { - int inputBits = inputValue.getPlatformKind().getSizeInBytes() * 8; - return emitNarrow(emitZeroExtend(inputValue, inputBits, XWORD.getSizeInBits()), inputBits); - } - - @Override - public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) { - assert fromBits <= toBits && toBits <= 64; - if (fromBits == toBits) { - return inputValue; - } - Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD)); - AllocatableValue inputAllocatable = asAllocatable(inputValue); - if (fromBits == 32) { - getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result)); - } else { - Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits))); - getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, mask, result)); - } - return result; - } - - @Override - public AllocatableValue emitReinterpret(LIRKind to, Value inputVal) { - SPARCKind fromKind = (SPARCKind) inputVal.getPlatformKind(); - SPARCKind toKind = (SPARCKind) to.getPlatformKind(); - AllocatableValue input = asAllocatable(inputVal); - Variable result = getLIRGen().newVariable(to); - // These cases require a move between CPU and FPU registers: - if (fromKind.isFloat() != toKind.isFloat()) { - moveBetweenFpGp(result, input); - return result; - } else { - // Otherwise, just emit an ordinary move instruction. - // Instructions that move or generate 32-bit register values also set the upper 32 - // bits of the register to zero. - // Consequently, there is no need for a special zero-extension move. - return emitConvertMove(to, input); - } - } - - @Override - public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) { - SPARCAddressValue loadAddress = getLIRGen().asAddressValue(address); - Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind)); - getLIRGen().append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state)); - return result; - } - - @Override - public void emitStore(ValueKind kind, Value address, Value inputVal, LIRFrameState state) { - SPARCAddressValue storeAddress = getLIRGen().asAddressValue(address); - if (isJavaConstant(inputVal)) { - JavaConstant c = asJavaConstant(inputVal); - if (c.isDefaultForKind()) { - getLIRGen().append(new StoreConstantOp(kind.getPlatformKind(), storeAddress, c, state)); - return; - } - } - Variable input = getLIRGen().load(inputVal); - getLIRGen().append(new StoreOp(kind.getPlatformKind(), storeAddress, input, state)); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCImmediateAddressNode.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; - -import jdk.vm.ci.meta.AllocatableValue; - -/** - * Represents an address of the form [base + simm13]. - */ -@NodeInfo -public class SPARCImmediateAddressNode extends AddressNode implements LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(SPARCImmediateAddressNode.class); - - @Input private ValueNode base; - private int displacement; - - public SPARCImmediateAddressNode(ValueNode base, int displacement) { - super(TYPE); - assert SPARCAssembler.isSimm13(displacement); - this.base = base; - this.displacement = displacement; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - SPARCLIRGenerator tool = (SPARCLIRGenerator) gen.getLIRGeneratorTool(); - - AllocatableValue baseValue = tool.asAllocatable(gen.operand(base)); - - LIRKind kind = tool.getLIRKind(stamp(NodeView.DEFAULT)); - AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); - if (baseReference != null) { - kind = kind.makeDerivedReference(baseReference); - } - - gen.setResult(this, new SPARCImmediateAddressValue(kind, baseValue, displacement)); - } - - @Override - public ValueNode getBase() { - return base; - } - - @Override - public long getMaxConstantDisplacement() { - return displacement; - } - - @Override - public ValueNode getIndex() { - return null; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIndexedAddressNode.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.lir.sparc.SPARCIndexedAddressValue; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.address.AddressNode; -import org.graalvm.compiler.nodes.spi.LIRLowerable; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; - -import jdk.vm.ci.meta.AllocatableValue; - -/** - * Represents an address of the form [base + index]. - */ -@NodeInfo -public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable { - - public static final NodeClass TYPE = NodeClass.create(SPARCIndexedAddressNode.class); - - @Input private ValueNode base; - @Input private ValueNode index; - - public SPARCIndexedAddressNode(ValueNode base, ValueNode index) { - super(TYPE); - this.base = base; - this.index = index; - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - SPARCLIRGenerator tool = (SPARCLIRGenerator) gen.getLIRGeneratorTool(); - - AllocatableValue baseValue = tool.asAllocatable(gen.operand(base)); - AllocatableValue indexValue = tool.asAllocatable(gen.operand(index)); - - AllocatableValue baseReference = LIRKind.derivedBaseFromValue(baseValue); - AllocatableValue indexReference = LIRKind.derivedBaseFromValue(indexValue); - - LIRKind kind = LIRKind.combineDerived(tool.getLIRKind(stamp(NodeView.DEFAULT)), baseReference, indexReference); - gen.setResult(this, new SPARCIndexedAddressValue(kind, baseValue, indexValue)); - } - - @Override - public ValueNode getBase() { - return base; - } - - public void setBase(ValueNode base) { - updateUsages(this.base, base); - this.base = base; - } - - @Override - public ValueNode getIndex() { - return index; - } - - public void setIndex(ValueNode index) { - updateUsages(this.index, index); - this.index = index; - } - - @Override - public long getMaxConstantDisplacement() { - return Long.MAX_VALUE; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCIntegerCompareCanonicalizationPhase.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015, 2020, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.nodes.ConstantNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.CompareNode; -import org.graalvm.compiler.nodes.calc.SignExtendNode; -import org.graalvm.compiler.phases.Phase; - -import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.meta.JavaConstant; - -/** - * SPARC only supports 32 and 64 bit integer compare. - * - * This phase turns {@link CompareNode}s which have {@link IntegerStamp} as input and its bit-width - * is not 32 or 64 bit into either a 32 or 64 bit compare by sign extending the input values. - * - * Why we do this in the HIR instead in the LIR? This enables the pattern matcher - * {@link SPARCNodeMatchRules#signExtend(SignExtendNode, org.graalvm.compiler.nodes.memory.AddressableMemoryAccess)} - * to do it's job and replace loads with sign extending ones. - */ -public class SPARCIntegerCompareCanonicalizationPhase extends Phase { - @Override - protected void run(StructuredGraph graph) { - for (Node n : graph.getNodes()) { - if (n instanceof CompareNode) { - CompareNode enode = (CompareNode) n; - min32(enode, enode.getX()); - min32(enode, enode.getY()); - } - } - } - - private static void min32(CompareNode enode, ValueNode v) { - Stamp s = v.stamp(NodeView.DEFAULT); - if (s instanceof IntegerStamp) { - int bits = ((IntegerStamp) s).getBits(); - if (bits != 32 && bits != 64) { - if (bits <= 32) { - bits = 32; - } else { - bits = 64; - } - ValueNode replacement; - if (v instanceof ConstantNode) { - JavaConstant newConst; - if (bits == 32) { - newConst = JavaConstant.forInt(v.asJavaConstant().asInt()); - } else if (bits == 64) { - newConst = JavaConstant.forLong(v.asJavaConstant().asLong()); - } else { - throw GraalError.shouldNotReachHere(); - } - long mask = CodeUtil.mask(bits); - replacement = v.graph().addOrUnique(new ConstantNode(newConst, IntegerStamp.stampForMask(bits, newConst.asLong() & mask, newConst.asLong() & mask))); - } else { - replacement = v.graph().addOrUnique(new SignExtendNode(v, bits)); - } - v.replaceAtUsages(replacement, x -> x == enode); - } - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Copyright (c) 2009, 2019, 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 org.graalvm.compiler.core.sparc; - -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVDCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FMOVSCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.MOVICC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; -import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static jdk.vm.ci.sparc.SPARCKind.SINGLE; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.calc.Condition; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.core.common.spi.LIRKindTool; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIR; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRValueUtil; -import org.graalvm.compiler.lir.LabelRef; -import org.graalvm.compiler.lir.StandardOp.NoOp; -import org.graalvm.compiler.lir.SwitchStrategy; -import org.graalvm.compiler.lir.Variable; -import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.compiler.lir.gen.LIRGenerator; -import org.graalvm.compiler.lir.sparc.SPARCAddressValue; -import org.graalvm.compiler.lir.sparc.SPARCArrayEqualsOp; -import org.graalvm.compiler.lir.sparc.SPARCByteSwapOp; -import org.graalvm.compiler.lir.sparc.SPARCCall; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.BranchOp; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.CondMoveOp; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.TableSwitchOp; -import org.graalvm.compiler.lir.sparc.SPARCFloatCompareOp; -import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; -import org.graalvm.compiler.lir.sparc.SPARCJumpOp; -import org.graalvm.compiler.lir.sparc.SPARCLoadConstantTableBaseOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.LoadOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.MembarOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.StackLoadAddressOp; -import org.graalvm.compiler.lir.sparc.SPARCOP3Op; -import org.graalvm.compiler.lir.sparc.SPARCPauseOp; -import org.graalvm.compiler.phases.util.Providers; - -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.meta.ValueKind; -import jdk.vm.ci.sparc.SPARC; -import jdk.vm.ci.sparc.SPARCKind; - -/** - * This class implements the SPARC specific portion of the LIR generator. - */ -public abstract class SPARCLIRGenerator extends LIRGenerator { - - private SPARCLoadConstantTableBaseOp loadConstantTableBaseOp; - private final ConstantTableBaseProvider constantTableBaseProvider; - - public static final class ConstantTableBaseProvider { - private Variable constantTableBase; - private boolean useConstantTableBase = false; - - public Variable getConstantTableBase() { - useConstantTableBase = true; - return constantTableBase; - } - } - - public SPARCLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, Providers providers, LIRGenerationResult lirGenRes, - ConstantTableBaseProvider constantTableBaseProvider) { - super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); - this.constantTableBaseProvider = constantTableBaseProvider; - } - - @Override - protected JavaConstant zapValueForKind(PlatformKind kind) { - long dead = 0xDEADDEADDEADDEADL; - switch ((SPARCKind) kind) { - case BYTE: - return JavaConstant.forByte((byte) dead); - case HWORD: - return JavaConstant.forShort((short) dead); - case WORD: - return JavaConstant.forInt((int) dead); - case XWORD: - return JavaConstant.forLong(dead); - case SINGLE: - case V32_BYTE: - case V32_HWORD: - return JavaConstant.forFloat(Float.intBitsToFloat((int) dead)); - case DOUBLE: - case V64_BYTE: - case V64_HWORD: - case V64_WORD: - return JavaConstant.forDouble(Double.longBitsToDouble(dead)); - default: - throw new IllegalArgumentException(kind.toString()); - } - } - - /** - * The SPARC backend only uses WORD and DWORD values in registers because except to the ld/st - * instructions no instruction deals either with 32 or 64 bits. This function converts small - * integer kinds to WORD. - */ - @Override - public > K toRegisterKind(K kind) { - switch ((SPARCKind) kind.getPlatformKind()) { - case BYTE: - case HWORD: - return kind.changeType(SPARCKind.WORD); - default: - return kind; - } - } - - public SPARCAddressValue asAddressValue(Value address) { - if (address instanceof SPARCAddressValue) { - return (SPARCAddressValue) address; - } else { - ValueKind kind = address.getValueKind(); - if (address instanceof JavaConstant) { - long displacement = ((JavaConstant) address).asLong(); - if (SPARCAssembler.isSimm13(displacement)) { - return new SPARCImmediateAddressValue(kind, SPARC.g0.asValue(kind), (int) displacement); - } - } - return new SPARCImmediateAddressValue(kind, asAllocatable(address), 0); - } - } - - @Override - public Variable emitAddress(AllocatableValue stackslot) { - Variable result = newVariable(LIRKind.value(target().arch.getWordKind())); - append(new StackLoadAddressOp(result, stackslot)); - return result; - } - - @Override - public void emitReturn(JavaKind javaKind, Value input) { - AllocatableValue operand = Value.ILLEGAL; - if (input != null) { - operand = resultOperandFor(javaKind, input.getValueKind()); - emitMove(operand, input); - } - append(new ReturnOp(operand)); - } - - @Override - public void emitJump(LabelRef label) { - append(new SPARCJumpOp(label)); - } - - @Override - public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, - double trueDestinationProbability) { - AllocatableValue left; - Value right; - Condition actualCondition; - if (isJavaConstant(x)) { - left = load(y); - right = loadSimm13(x); - actualCondition = cond.mirror(); - } else { - left = load(x); - right = loadSimm13(y); - actualCondition = cond; - } - SPARCKind actualCmpKind = (SPARCKind) cmpKind; - if (actualCmpKind.isInteger()) { - assert actualCmpKind.equals(XWORD) || actualCmpKind.equals(WORD) : "SPARC does not support compare of: " + actualCmpKind; - append(new SPARCControlFlow.CompareBranchOp(left, right, actualCondition, trueDestination, falseDestination, actualCmpKind, unorderedIsTrue, trueDestinationProbability)); - } else if (actualCmpKind.isFloat()) { - emitFloatCompare(actualCmpKind, x, y, Fcc0); - ConditionFlag cf = SPARCControlFlow.fromCondition(false, cond, unorderedIsTrue); - append(new SPARCControlFlow.BranchOp(cf, trueDestination, falseDestination, actualCmpKind, trueDestinationProbability)); - } else { - throw GraalError.shouldNotReachHere(); - } - } - - @Override - public void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpLIRKind, double overflowProbability) { - SPARCKind cmpKind = (SPARCKind) cmpLIRKind.getPlatformKind(); - append(new BranchOp(ConditionFlag.OverflowSet, overflow, noOverflow, cmpKind, overflowProbability)); - } - - @Override - public void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) { - emitIntegerTest(left, right); - append(new BranchOp(ConditionFlag.Equal, trueDestination, falseDestination, (SPARCKind) left.getPlatformKind(), trueDestinationProbability)); - } - - private void emitIntegerTest(Value a, Value b) { - assert ((SPARCKind) a.getPlatformKind()).isInteger(); - if (LIRValueUtil.isVariable(b)) { - append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadSimm13(a))); - } else { - append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadSimm13(b))); - } - } - - private Value loadSimm11(Value value) { - if (isJavaConstant(value)) { - JavaConstant c = asJavaConstant(value); - if (c.isNull() || SPARCAssembler.isSimm11(c)) { - return value; - } - } - return load(value); - } - - public Value loadSimm13(Value value) { - if (isJavaConstant(value)) { - JavaConstant c = asJavaConstant(value); - if (c.isNull() || SPARCAssembler.isSimm13(c)) { - return value; - } - } - return load(value); - } - - @Override - public Value loadNonConst(Value value) { - // SPARC does not support a proper way of loadNonConst. Please use the appropriate - // loadSimm11 or loadSimm13 variants. - throw GraalError.shouldNotReachHere("This operation is not available for SPARC."); - } - - @Override - public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { - // Emit compare - SPARCKind cmpSPARCKind = (SPARCKind) cmpKind; - boolean mirrored = emitCompare(cmpSPARCKind, left, right); - - // Emit move - Value actualTrueValue = trueValue; - Value actualFalseValue = falseValue; - SPARCKind valueKind = (SPARCKind) trueValue.getPlatformKind(); - CMOV cmove; - if (valueKind.isFloat()) { - actualTrueValue = load(trueValue); // Floats cannot be immediate at all - actualFalseValue = load(falseValue); - cmove = valueKind.equals(SINGLE) ? FMOVSCC : FMOVDCC; - } else if (valueKind.isInteger()) { - actualTrueValue = loadSimm11(trueValue); - actualFalseValue = loadSimm11(falseValue); - cmove = MOVICC; - } else { - throw GraalError.shouldNotReachHere(); - } - Variable result = newVariable(trueValue.getValueKind()); - ConditionFlag finalCondition = SPARCControlFlow.fromCondition(cmpSPARCKind.isInteger(), mirrored ? cond.mirror() : cond, unorderedIsTrue); - CC cc = CC.forKind(cmpSPARCKind); - append(new CondMoveOp(cmove, cc, finalCondition, actualTrueValue, actualFalseValue, result)); - return result; - } - - /** - * This method emits the compare instruction, and may reorder the operands. It returns true if - * it did so. - * - * @param cmpKind Kind how a and b have to be compared - * @param a the left operand of the comparison - * @param b the right operand of the comparison - * @return true if the left and right operands were switched, false otherwise - */ - protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) { - boolean mirrored; - if (cmpKind.isInteger()) { // Integer case - mirrored = emitIntegerCompare(cmpKind, a, b); - } else if (cmpKind.isFloat()) { // Float case - mirrored = false; // No mirroring done on floats - emitFloatCompare(cmpKind, a, b, Fcc0); - } else { - throw GraalError.shouldNotReachHere(); - } - return mirrored; - } - - private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) { - boolean mirrored; - assert cmpKind.isInteger(); - AllocatableValue left; - Value right; - if (LIRValueUtil.isVariable(b)) { - left = load(b); - right = loadSimm13(a); - mirrored = true; - } else { - left = load(a); - right = loadSimm13(b); - mirrored = false; - } - int compareBytes = cmpKind.getSizeInBytes(); - // SPARC compares 32 or 64 bits - if (compareBytes < left.getPlatformKind().getSizeInBytes()) { - left = asAllocatable(arithmeticLIRGen.emitSignExtend(left, cmpKind.getSizeInBits(), XWORD.getSizeInBits())); - } - if (compareBytes < right.getPlatformKind().getSizeInBytes()) { - right = arithmeticLIRGen.emitSignExtend(right, cmpKind.getSizeInBits(), XWORD.getSizeInBits()); - } - append(SPARCOP3Op.newBinaryVoid(Subcc, left, right)); - return mirrored; - } - - private void emitFloatCompare(SPARCKind cmpJavaKind, Value a, Value b, CC cc) { - Opfs floatCompareOpcode; - assert cmpJavaKind.isFloat(); - switch (cmpJavaKind) { - case DOUBLE: - floatCompareOpcode = Fcmpd; - break; - case SINGLE: - floatCompareOpcode = Fcmps; - break; - default: - throw GraalError.shouldNotReachHere(); - } - append(new SPARCFloatCompareOp(floatCompareOpcode, cc, load(a), load(b))); - } - - @Override - public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) { - emitIntegerTest(left, right); - Variable result = newVariable(trueValue.getValueKind()); - ConditionFlag flag = SPARCControlFlow.fromCondition(true, Condition.EQ, false); - CC cc = CC.forKind(left.getPlatformKind()); - append(new CondMoveOp(MOVICC, cc, flag, loadSimm11(trueValue), loadSimm11(falseValue), result)); - return result; - } - - @Override - protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { - long maxOffset = linkage.getMaxCallTargetOffset(); - if (SPARCAssembler.isWordDisp30(maxOffset)) { - append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info)); - } else { - append(new SPARCCall.DirectFarForeignCallOp(linkage, result, arguments, temps, info)); - } - } - - @Override - public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) { - Variable scratchValue = newVariable(key.getValueKind()); - AllocatableValue base = AllocatableValue.ILLEGAL; - for (Constant c : strategy.getKeyConstants()) { - if (!getMoveFactory().canInlineConstant(c)) { - base = constantTableBaseProvider.getConstantTableBase(); - break; - } - } - append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue)); - } - - protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) { - return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue); - } - - @Override - protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) { - // Making a copy of the switch value is necessary because jump table destroys the input - // value - Variable tmp = newVariable(key.getValueKind()); - emitMove(tmp, key); - append(new TableSwitchOp(lowKey, defaultTarget, targets, tmp, newVariable(LIRKind.value(target().arch.getWordKind())))); - } - - protected SPARC getArchitecture() { - return (SPARC) target().arch; - } - - @Override - public Variable emitByteSwap(Value input) { - Variable result = newVariable(LIRKind.combine(input)); - append(new SPARCByteSwapOp(this, result, asAllocatable(input))); - return result; - } - - @Override - public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, boolean directPointers) { - Variable result = newVariable(LIRKind.value(SPARCKind.WORD)); - append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length), directPointers)); - return result; - } - - @Override - public void emitMembar(int barriers) { - int necessaryBarriers = target().arch.requiredBarriers(barriers); - if (target().isMP && necessaryBarriers != 0) { - append(new MembarOp(necessaryBarriers)); - } - } - - @Override - public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { - append(new ReturnOp(Value.ILLEGAL)); - } - - public Value emitSignExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) { - SPARCAddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(resultKind); - append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state, true)); - return result; - } - - public Value emitZeroExtendLoad(LIRKind kind, LIRKind resultKind, Value address, LIRFrameState state) { - SPARCAddressValue loadAddress = asAddressValue(address); - Variable result = newVariable(resultKind); - append(new LoadOp(kind.getPlatformKind(), result, loadAddress, state)); - return result; - } - - @Override - public void emitNullCheck(Value address, LIRFrameState state) { - PlatformKind kind = address.getPlatformKind(); - assert kind == XWORD : address + " - " + kind + " not an object!"; - append(new NullCheckOp(asAddressValue(address), state)); - } - - public void emitLoadConstantTableBase() { - constantTableBaseProvider.constantTableBase = newVariable(LIRKind.value(XWORD)); - int nextPosition = getResult().getLIR().getLIRforBlock(getCurrentBlock()).size(); - NoOp placeHolder = append(new NoOp(getCurrentBlock(), nextPosition)); - loadConstantTableBaseOp = new SPARCLoadConstantTableBaseOp(constantTableBaseProvider.constantTableBase, placeHolder); - } - - @Override - public void beforeRegisterAllocation() { - LIR lir = getResult().getLIR(); - loadConstantTableBaseOp.setAlive(lir, constantTableBaseProvider.useConstantTableBase); - } - - @Override - public void emitPause() { - append(new SPARCPauseOp()); - } - - @Override - public void emitSpeculationFence() { - throw GraalError.unimplemented(); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRKindTool.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.spi.LIRKindTool; -import org.graalvm.compiler.debug.GraalError; - -import jdk.vm.ci.sparc.SPARCKind; - -public class SPARCLIRKindTool implements LIRKindTool { - - @Override - public LIRKind getIntegerKind(int bits) { - if (bits <= 8) { - return LIRKind.value(SPARCKind.BYTE); - } else if (bits <= 16) { - return LIRKind.value(SPARCKind.HWORD); - } else if (bits <= 32) { - return LIRKind.value(SPARCKind.WORD); - } else { - assert bits <= 64; - return LIRKind.value(SPARCKind.XWORD); - } - } - - @Override - public LIRKind getFloatingKind(int bits) { - switch (bits) { - case 32: - return LIRKind.value(SPARCKind.SINGLE); - case 64: - return LIRKind.value(SPARCKind.DOUBLE); - default: - throw GraalError.shouldNotReachHere(); - } - } - - @Override - public LIRKind getObjectKind() { - return LIRKind.reference(SPARCKind.XWORD); - } - - @Override - public LIRKind getWordKind() { - return LIRKind.value(SPARCKind.XWORD); - } - - @Override - public LIRKind getNarrowOopKind() { - return LIRKind.compressedReference(SPARCKind.WORD); - } - - @Override - public LIRKind getNarrowPointerKind() { - return LIRKind.value(SPARCKind.WORD); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCMoveFactory.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.sparc; - -import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; -import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.core.common.type.DataPointerConstant; -import org.graalvm.compiler.core.sparc.SPARCLIRGenerator.ConstantTableBaseProvider; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRInstruction; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; -import org.graalvm.compiler.lir.sparc.SPARCAddressValue; -import org.graalvm.compiler.lir.sparc.SPARCMove; -import org.graalvm.compiler.lir.sparc.SPARCMove.LoadAddressOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.Move; - -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.Value; - -public class SPARCMoveFactory implements MoveFactory { - - protected final ConstantTableBaseProvider constantTableBaseProvider; - - public SPARCMoveFactory(ConstantTableBaseProvider constantTableBaseProvider) { - this.constantTableBaseProvider = constantTableBaseProvider; - } - - @Override - public LIRInstruction createMove(AllocatableValue dst, Value src) { - boolean srcIsSlot = isStackSlotValue(src); - boolean dstIsSlot = isStackSlotValue(dst); - if (isConstantValue(src)) { - return createLoad(dst, asConstant(src)); - } else if (src instanceof SPARCAddressValue) { - return new LoadAddressOp(dst, (SPARCAddressValue) src); - } else { - assert src instanceof AllocatableValue; - if (srcIsSlot && dstIsSlot) { - throw GraalError.shouldNotReachHere(src.getClass() + " " + dst.getClass()); - } else { - return new Move(dst, (AllocatableValue) src); - } - } - } - - @Override - public LIRInstruction createStackMove(AllocatableValue result, AllocatableValue input) { - return new SPARCMove.Move(result, input); - } - - @Override - public LIRInstruction createLoad(AllocatableValue dst, Constant src) { - if (src instanceof JavaConstant) { - JavaConstant javaConstant = (JavaConstant) src; - if (canInlineConstant(javaConstant)) { - return new SPARCMove.LoadInlineConstant(javaConstant, dst); - } else { - return new SPARCMove.LoadConstantFromTable(javaConstant, constantTableBaseProvider.getConstantTableBase(), dst); - } - } else if (src instanceof DataPointerConstant) { - return new SPARCMove.LoadDataAddressOp(dst, (DataPointerConstant) src); - } else { - throw GraalError.shouldNotReachHere(src.getClass().toString()); - } - } - - @Override - public LIRInstruction createStackLoad(AllocatableValue result, Constant input) { - if (input instanceof DataPointerConstant) { - throw GraalError.shouldNotReachHere("unsupported constant for stack load: " + input); - } - return createLoad(result, input); - } - - @Override - public boolean canInlineConstant(Constant con) { - if (con instanceof JavaConstant) { - JavaConstant c = (JavaConstant) con; - switch (c.getJavaKind()) { - case Boolean: - case Byte: - case Char: - case Short: - case Int: - return SPARCAssembler.isSimm13(c.asInt()); - case Long: - return SPARCAssembler.isSimm13(c.asLong()); - case Object: - return c.isNull(); - default: - return false; - } - } - return false; - } - - @Override - public boolean allowConstantToStackMove(Constant value) { - return false; - } - -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeLIRBuilder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2009, 2018, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.core.gen.NodeLIRBuilder; -import org.graalvm.compiler.lir.LabelRef; -import org.graalvm.compiler.lir.StandardOp.JumpOp; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import org.graalvm.compiler.lir.sparc.SPARCJumpOp; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; - -/** - * This class implements the SPARC specific portion of the LIR generator. - */ -public abstract class SPARCNodeLIRBuilder extends NodeLIRBuilder { - - public SPARCNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) { - super(graph, lirGen, nodeMatchRules); - } - - @Override - protected boolean peephole(ValueNode valueNode) { - // No peephole optimizations for now - return false; - } - - @Override - protected JumpOp newJumpOp(LabelRef ref) { - return new SPARCJumpOp(ref); - } - - @Override - public SPARCLIRGenerator getLIRGeneratorTool() { - return (SPARCLIRGenerator) super.getLIRGeneratorTool(); - } - - @Override - protected void emitPrologue(StructuredGraph graph) { - getLIRGeneratorTool().emitLoadConstantTableBase(); - super.emitPrologue(graph); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2009, 2020, 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 org.graalvm.compiler.core.sparc; - -import static jdk.vm.ci.sparc.SPARCKind.BYTE; -import static jdk.vm.ci.sparc.SPARCKind.HWORD; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.calc.CanonicalCondition; -import org.graalvm.compiler.core.common.calc.Condition; -import org.graalvm.compiler.core.gen.NodeMatchRules; -import org.graalvm.compiler.core.match.ComplexMatchResult; -import org.graalvm.compiler.core.match.MatchRule; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LabelRef; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import org.graalvm.compiler.lir.sparc.SPARCAddressValue; -import org.graalvm.compiler.nodes.DeoptimizingNode; -import org.graalvm.compiler.nodes.IfNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.CompareNode; -import org.graalvm.compiler.nodes.calc.SignExtendNode; -import org.graalvm.compiler.nodes.calc.ZeroExtendNode; -import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode; -import org.graalvm.compiler.nodes.memory.AddressableMemoryAccess; -import org.graalvm.compiler.nodes.memory.LIRLowerableAccess; -import org.graalvm.compiler.nodes.memory.MemoryAccess; - -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARCKind; - -/** - * This class implements the SPARC specific portion of the LIR generator. - */ -public class SPARCNodeMatchRules extends NodeMatchRules { - - public SPARCNodeMatchRules(LIRGeneratorTool gen) { - super(gen); - } - - protected LIRFrameState getState(MemoryAccess access) { - if (access instanceof DeoptimizingNode) { - return state((DeoptimizingNode) access); - } - return null; - } - - protected LIRKind getLirKind(LIRLowerableAccess access) { - return gen.getLIRKind(access.getAccessStamp(NodeView.DEFAULT)); - } - - private ComplexMatchResult emitSignExtendMemory(AddressableMemoryAccess access, int fromBits, int toBits) { - assert fromBits <= toBits && toBits <= 64; - SPARCKind toKind = null; - SPARCKind fromKind = null; - if (fromBits == toBits) { - return null; - } - toKind = toBits > 32 ? XWORD : WORD; - switch (fromBits) { - case 8: - fromKind = BYTE; - break; - case 16: - fromKind = HWORD; - break; - case 32: - fromKind = WORD; - break; - default: - throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); - } - SPARCKind localFromKind = fromKind; - SPARCKind localToKind = toKind; - return builder -> { - return getLIRGeneratorTool().emitSignExtendLoad(LIRKind.value(localFromKind), LIRKind.value(localToKind), operand(access.getAddress()), getState(access)); - }; - } - - private ComplexMatchResult emitZeroExtendMemory(AddressableMemoryAccess access, int fromBits, int toBits) { - assert fromBits <= toBits && toBits <= 64; - SPARCKind toKind = null; - SPARCKind fromKind = null; - if (fromBits == toBits) { - return null; - } - toKind = toBits > 32 ? XWORD : WORD; - switch (fromBits) { - case 8: - fromKind = BYTE; - break; - case 16: - fromKind = HWORD; - break; - case 32: - fromKind = WORD; - break; - default: - throw GraalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)"); - } - SPARCKind localFromKind = fromKind; - SPARCKind localToKind = toKind; - return builder -> { - // Loads are always zero extending load - return getLIRGeneratorTool().emitZeroExtendLoad(LIRKind.value(localFromKind), LIRKind.value(localToKind), operand(access.getAddress()), getState(access)); - }; - } - - @MatchRule("(SignExtend Read=access)") - @MatchRule("(SignExtend FloatingRead=access)") - @MatchRule("(SignExtend VolatileRead=access)") - public ComplexMatchResult signExtend(SignExtendNode root, AddressableMemoryAccess access) { - return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits()); - } - - @MatchRule("(ZeroExtend Read=access)") - @MatchRule("(ZeroExtend FloatingRead=access)") - @MatchRule("(ZeroExtend VolatileRead=access)") - public ComplexMatchResult zeroExtend(ZeroExtendNode root, AddressableMemoryAccess access) { - return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits()); - } - - @MatchRule("(If (ObjectEquals=compare value LogicCompareAndSwap=cas))") - @MatchRule("(If (PointerEquals=compare value LogicCompareAndSwap=cas))") - @MatchRule("(If (FloatEquals=compare value LogicCompareAndSwap=cas))") - @MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))") - public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) { - JavaConstant constant = value.asJavaConstant(); - assert compare.condition() == CanonicalCondition.EQ; - if (constant != null && cas.hasExactlyOneUsage()) { - long constantValue = constant.asLong(); - boolean successIsTrue; - if (constantValue == 0) { - successIsTrue = false; - } else if (constantValue == 1) { - successIsTrue = true; - } else { - return null; - } - return builder -> { - LIRKind kind = getLirKind(cas); - LabelRef trueLabel = getLIRBlock(root.trueSuccessor()); - LabelRef falseLabel = getLIRBlock(root.falseSuccessor()); - double trueLabelProbability = root.probability(root.trueSuccessor()); - Value expectedValue = operand(cas.getExpectedValue()); - Value newValue = operand(cas.getNewValue()); - SPARCAddressValue address = (SPARCAddressValue) operand(cas.getAddress()); - Condition condition = successIsTrue ? Condition.EQ : Condition.NE; - - Value result = getLIRGeneratorTool().emitValueCompareAndSwap(kind, address, expectedValue, newValue); - getLIRGeneratorTool().emitCompareBranch(kind.getPlatformKind(), result, expectedValue, condition, false, trueLabel, falseLabel, trueLabelProbability); - return null; - }; - } - return null; - } - - @Override - public SPARCLIRGenerator getLIRGeneratorTool() { - return (SPARCLIRGenerator) super.getLIRGeneratorTool(); - } - - protected SPARCArithmeticLIRGenerator getArithmeticLIRGenerator() { - return (SPARCArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesCreator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesCreator.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCSuitesCreator.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.sparc; - -import java.util.ListIterator; - -import org.graalvm.compiler.java.DefaultSuitesCreator; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.common.ExpandLogicPhase; -import org.graalvm.compiler.phases.tiers.CompilerConfiguration; -import org.graalvm.compiler.phases.tiers.LowTierContext; -import org.graalvm.compiler.phases.tiers.Suites; - -public class SPARCSuitesCreator extends DefaultSuitesCreator { - - public SPARCSuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins) { - super(compilerConfiguration, plugins); - } - - @Override - public Suites createSuites(OptionValues options) { - Suites s = super.createSuites(options); - ListIterator> l = s.getLowTier().findPhase(ExpandLogicPhase.class); - while (PhaseSuite.findNextPhase(l, ExpandLogicPhase.class)) { - // Search for last occurrence of ExpandLogicPhase - } - l.previous(); - l.add(new SPARCIntegerCompareCanonicalizationPhase()); - return s; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SparcLoweringProviderMixin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SparcLoweringProviderMixin.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SparcLoweringProviderMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2019, 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 org.graalvm.compiler.core.sparc; - -import org.graalvm.compiler.nodes.spi.LoweringProvider; - -public interface SparcLoweringProviderMixin extends LoweringProvider { - - @Override - default Integer smallestCompareWidth() { - return 32; - } - - @Override - default boolean supportsBulkZeroing() { - return false; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.hotspot.sparc.test; - -import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; -import static org.junit.Assume.assumeTrue; - -import org.graalvm.compiler.core.test.backend.AllocatorTest; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.junit.Before; -import org.junit.Test; - -import jdk.vm.ci.sparc.SPARC; - -public class SPARCAllocatorTest extends AllocatorTest { - - private final GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig(); - - @Before - public void checkSPARC() { - assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC); - assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null); - } - - @Test - public void test1() { - testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); - } - - public static long test1snippet(long x) { - return x + 41; - } - - @Test - public void test2() { - testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); - } - - public static long test2snippet(long x) { - return x * 41; - } - - @Test - public void test3() { - testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0); - } - - public static long test3snippet(long x) { - return x / 41 + x % 41; - } - -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCDeoptimizeOp.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2012, 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCBlockEndOp; -import org.graalvm.compiler.lir.sparc.SPARCCall; - -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.sparc.SPARC; - -@Opcode("DEOPT") -final class SPARCDeoptimizeOp extends SPARCBlockEndOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCDeoptimizeOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(1); - @Temp AllocatableValue pcRegister; - @State private LIRFrameState info; - - SPARCDeoptimizeOp(LIRFrameState info, PlatformKind wordKind) { - super(TYPE, SIZE); - this.info = info; - pcRegister = SPARC.o7.asValue(LIRKind.value(wordKind)); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // TODO the patched call address looks odd (and is invalid) compared to other runtime calls: - // 0xffffffff749bb5fc: call 0xffffffff415a720c ; {runtime_call} - // [Exception Handler] - // 0xffffffff749bb604: call 0xffffffff749bb220 ; {runtime_call} - // 0xffffffff749bb608: nop - // [Deopt Handler Code] - // 0xffffffff749bb60c: call 0xffffffff748da540 ; {runtime_call} - // 0xffffffff749bb610: nop - SPARCCall.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP), null, info); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - * Copyright (c) 2013, 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isRegister; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARC.g5; -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i7; -import static jdk.vm.ci.sparc.SPARC.l0; -import static jdk.vm.ci.sparc.SPARC.l7; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o7; -import static jdk.vm.ci.sparc.SPARC.sp; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isGlobalRegister; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; -import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import jdk.internal.vm.compiler.collections.EconomicSet; -import jdk.internal.vm.compiler.collections.Equivalence; -import org.graalvm.compiler.asm.Assembler; -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.code.CompilationResult; -import org.graalvm.compiler.code.DataSection; -import org.graalvm.compiler.code.DataSection.Data; -import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; -import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; -import org.graalvm.compiler.core.gen.LIRGenerationProvider; -import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules; -import org.graalvm.compiler.debug.CounterKey; -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotDataBuilder; -import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.HotSpotHostBackend; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; -import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.stubs.Stub; -import org.graalvm.compiler.lir.InstructionValueConsumer; -import org.graalvm.compiler.lir.LIR; -import org.graalvm.compiler.lir.LIRInstruction; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; -import org.graalvm.compiler.lir.asm.DataBuilder; -import org.graalvm.compiler.lir.asm.FrameContext; -import org.graalvm.compiler.lir.framemap.FrameMap; -import org.graalvm.compiler.lir.framemap.FrameMapBuilder; -import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import org.graalvm.compiler.lir.sparc.SPARCCall; -import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; -import org.graalvm.compiler.lir.sparc.SPARCFrameMap; -import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate; -import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import org.graalvm.compiler.options.OptionValues; - -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.StackSlot; -import jdk.vm.ci.hotspot.HotSpotCallingConventionType; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -/** - * HotSpot SPARC specific backend. - */ -public class SPARCHotSpotBackend extends HotSpotHostBackend implements LIRGenerationProvider { - - private static final SizeEstimateStatistics CONSTANT_ESTIMATED_STATS = new SizeEstimateStatistics("ESTIMATE"); - private static final SizeEstimateStatistics CONSTANT_ACTUAL_STATS = new SizeEstimateStatistics("ACTUAL"); - - public SPARCHotSpotBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { - super(config, runtime, providers); - } - - private static class SizeEstimateStatistics { - private static final ConcurrentHashMap counters = new ConcurrentHashMap<>(); - private final String suffix; - - SizeEstimateStatistics(String suffix) { - super(); - this.suffix = suffix; - } - - public void add(Class c, int count, DebugContext debug) { - String name = SizeEstimateStatistics.class.getSimpleName() + "_" + c.getSimpleName() + "." + suffix; - CounterKey m = counters.computeIfAbsent(name, (n) -> DebugContext.counter(n)); - m.add(debug, count); - } - } - - @Override - protected FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) { - RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; - FrameMap frameMap = new SPARCFrameMap(getCodeCache(), registerConfigNonNull, this); - return new SPARCFrameMapBuilder(frameMap, getCodeCache(), registerConfigNonNull); - } - - @Override - public LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes) { - return new SPARCHotSpotLIRGenerator(getProviders(), getRuntime().getVMConfig(), lirGenRes); - } - - @Override - public NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen) { - return new SPARCHotSpotNodeLIRBuilder(graph, lirGen, new SPARCNodeMatchRules(lirGen)); - } - - @Override - protected void bangStackWithOffset(CompilationResultBuilder crb, int bangOffset) { - // Use SPARCAddress to get the final displacement including the stack bias. - SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; - SPARCAddress address = new SPARCAddress(sp, -bangOffset); - if (SPARCAssembler.isSimm13(address.getDisplacement())) { - masm.stx(g0, address); - } else { - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - assert isGlobalRegister(scratch) : "Only global (g1-g7) registers are allowed if the frame was not initialized here. Got register " + scratch; - masm.setx(address.getDisplacement(), scratch, false); - masm.stx(g0, new SPARCAddress(sp, scratch)); - } - } - } - - public class HotSpotFrameContext implements FrameContext { - - final boolean isStub; - - HotSpotFrameContext(boolean isStub) { - this.isStub = isStub; - } - - @Override - public boolean hasFrame() { - return true; - } - - @Override - public void enter(CompilationResultBuilder crb) { - final int frameSize = crb.frameMap.totalFrameSize(); - final int stackpointerChange = -frameSize; - SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; - if (!isStub) { - emitStackOverflowCheck(crb); - } - - if (SPARCAssembler.isSimm13(stackpointerChange)) { - masm.save(sp, stackpointerChange, sp); - } else { - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch; - masm.setx(stackpointerChange, scratch, false); - masm.save(sp, scratch, sp); - } - } - - if (ZapStackOnMethodEntry.getValue(crb.getOptions())) { - final int slotSize = 8; - for (int i = 0; i < frameSize / slotSize; ++i) { - // 0xC1C1C1C1 - masm.stx(g0, new SPARCAddress(sp, i * slotSize)); - } - } - } - - @Override - public void leave(CompilationResultBuilder crb) { - SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; - masm.restoreWindow(); - } - } - - @Override - public CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenRes, FrameMap frameMap, CompilationResult compilationResult, CompilationResultBuilderFactory factory) { - HotSpotLIRGenerationResult gen = (HotSpotLIRGenerationResult) lirGenRes; - LIR lir = gen.getLIR(); - assert gen.getDeoptimizationRescueSlot() == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame"; - - Stub stub = gen.getStub(); - Assembler masm = new SPARCMacroAssembler(getTarget()); - // On SPARC we always use stack frames. - HotSpotFrameContext frameContext = new HotSpotFrameContext(stub != null); - DataBuilder dataBuilder = new HotSpotDataBuilder(getCodeCache().getTarget()); - OptionValues options = lir.getOptions(); - DebugContext debug = lir.getDebug(); - CompilationResultBuilder crb = factory.createBuilder(getProviders().getCodeCache(), getProviders().getForeignCalls(), frameMap, masm, dataBuilder, frameContext, options, debug, - compilationResult, Register.None); - crb.setTotalFrameSize(frameMap.totalFrameSize()); - crb.setMaxInterpreterFrameSize(gen.getMaxInterpreterFrameSize()); - StackSlot deoptimizationRescueSlot = gen.getDeoptimizationRescueSlot(); - if (deoptimizationRescueSlot != null && stub == null) { - crb.compilationResult.setCustomStackAreaOffset(deoptimizationRescueSlot); - } - - if (stub != null) { - updateStub(stub, gen, frameMap); - } - assert registerSizePredictionValidator(crb, debug); - return crb; - } - - /** - * Registers a verifier which checks if the LIRInstructions estimate of constants size is - * greater or equal to the actual one. - */ - private static boolean registerSizePredictionValidator(final CompilationResultBuilder crb, DebugContext debug) { - /** - * Used to hold state between beforeOp and afterOp - */ - class ValidationState { - LIRInstruction op; - final DebugContext debug; - int constantSizeBefore; - - ValidationState(DebugContext debug) { - this.debug = debug; - } - - public void before(LIRInstruction before) { - assert op == null : "LIRInstruction " + op + " no after call received"; - op = before; - constantSizeBefore = calculateDataSectionSize(crb.compilationResult.getDataSection()); - } - - public void after(LIRInstruction after) { - assert after.equals(op) : "Instructions before/after don't match " + op + "/" + after; - int constantSizeAfter = calculateDataSectionSize(crb.compilationResult.getDataSection()); - int actual = constantSizeAfter - constantSizeBefore; - if (op instanceof SPARCLIRInstructionMixin) { - org.graalvm.compiler.lir.sparc.SPARCLIRInstructionMixin.SizeEstimate size = ((SPARCLIRInstructionMixin) op).estimateSize(); - assert size != null : "No size prediction available for op: " + op; - Class c = op.getClass(); - CONSTANT_ESTIMATED_STATS.add(c, size.constantSize, debug); - CONSTANT_ACTUAL_STATS.add(c, actual, debug); - assert size.constantSize >= actual : "Op " + op + " exceeded estimated constant size; predicted: " + size.constantSize + " actual: " + actual; - } else { - assert actual == 0 : "Op " + op + " emitted to DataSection without any estimate."; - } - op = null; - constantSizeBefore = 0; - } - } - final ValidationState state = new ValidationState(debug); - crb.setOpCallback(op -> state.before(op), op -> state.after(op)); - return true; - } - - private static int calculateDataSectionSize(DataSection ds) { - int sum = 0; - for (Data d : ds) { - sum += d.getSize(); - } - return sum; - } - - @Override - public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner) { - SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; - // TODO: (sa) Fold the two traversals into one - stuffDelayedControlTransfers(lir); - int constantSize = calculateConstantSize(lir); - boolean canUseImmediateConstantLoad = constantSize < (1 << 13); - masm.setImmediateConstantLoad(canUseImmediateConstantLoad); - FrameMap frameMap = crb.frameMap; - RegisterConfig regConfig = frameMap.getRegisterConfig(); - Label unverifiedStub = installedCodeOwner == null || installedCodeOwner.isStatic() ? null : new Label(); - for (int i = 0; i < 2; i++) { - if (i > 0) { - crb.resetForEmittingCode(); - lir.resetLabels(); - resetDelayedControlTransfers(lir); - } - - // Emit the prefix - if (unverifiedStub != null) { - crb.recordMark(config.MARKID_UNVERIFIED_ENTRY); - // We need to use JavaCall here because we haven't entered the frame yet. - CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, this); - Register inlineCacheKlass = g5; // see MacroAssembler::ic_call - - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - Register receiver = asRegister(cc.getArgument(0)); - SPARCAddress src = new SPARCAddress(receiver, config.hubOffset); - - masm.ldx(src, scratch); - masm.cmp(scratch, inlineCacheKlass); - } - BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, unverifiedStub); - masm.nop(); // delay slot - } - - masm.align(config.codeEntryAlignment); - crb.recordMark(config.MARKID_OSR_ENTRY); - crb.recordMark(config.MARKID_VERIFIED_ENTRY); - - // Emit code for the LIR - crb.emit(lir); - } - profileInstructions(lir, crb); - - HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; - HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); - if (!frameContext.isStub) { - crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); - SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null); - crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); - SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, null); - } else { - // No need to emit the stubs for entries back into the method since - // it has no calls that can cause such "return" entries - } - - if (unverifiedStub != null) { - masm.bind(unverifiedStub); - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER)); - } - } - masm.peephole(); - } - - private static int calculateConstantSize(LIR lir) { - int size = 0; - for (AbstractBlockBase block : lir.codeEmittingOrder()) { - if (block == null) { - continue; - } - for (LIRInstruction inst : lir.getLIRforBlock(block)) { - if (inst instanceof SPARCLIRInstructionMixin) { - SizeEstimate pred = ((SPARCLIRInstructionMixin) inst).estimateSize(); - if (pred != null) { - size += pred.constantSize; - } - } - } - } - return size; - } - - private static void resetDelayedControlTransfers(LIR lir) { - for (AbstractBlockBase block : lir.codeEmittingOrder()) { - if (block == null) { - continue; - } - for (LIRInstruction inst : lir.getLIRforBlock(block)) { - if (inst instanceof SPARCDelayedControlTransfer) { - ((SPARCDelayedControlTransfer) inst).resetState(); - } - } - } - } - - /** - * Fix-up over whole LIR. - * - * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase) - * @param l - */ - private static void stuffDelayedControlTransfers(LIR l) { - for (AbstractBlockBase b : l.codeEmittingOrder()) { - if (b != null) { - stuffDelayedControlTransfers(l, b); - } - } - } - - /** - * Tries to put DelayedControlTransfer instructions and DelayableLIRInstructions together. Also - * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if - * possible. - */ - private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase block) { - ArrayList instructions = l.getLIRforBlock(block); - if (instructions.size() >= 2) { - LIRDependencyAccumulator acc = new LIRDependencyAccumulator(); - SPARCDelayedControlTransfer delayedTransfer = null; - int delayTransferPosition = -1; - for (int i = instructions.size() - 1; i >= 0; i--) { - LIRInstruction inst = instructions.get(i); - boolean adjacent = delayTransferPosition - i == 1; - if (!adjacent || inst.destroysCallerSavedRegisters() || leavesRegisterWindow(inst)) { - delayedTransfer = null; - } - if (inst instanceof SPARCDelayedControlTransfer) { - delayedTransfer = (SPARCDelayedControlTransfer) inst; - acc.start(inst); - delayTransferPosition = i; - } else if (delayedTransfer != null) { - boolean overlap = acc.add(inst); - if (!overlap && inst instanceof SPARCTailDelayedLIRInstruction) { - // We have found a non overlapping LIR instruction which can be delayed - ((SPARCTailDelayedLIRInstruction) inst).setDelayedControlTransfer(delayedTransfer); - delayedTransfer = null; - } - } - } - } - } - - private static boolean leavesRegisterWindow(LIRInstruction inst) { - return inst instanceof SPARCLIRInstructionMixin && ((SPARCLIRInstructionMixin) inst).leavesRegisterWindow(); - } - - /** - * Accumulates inputs/outputs/temp/alive in a set along we walk back the LIRInstructions and - * detects, if there is any overlap. In this way LIRInstructions can be detected, which can be - * moved nearer to the DelayedControlTransfer instruction. - */ - private static class LIRDependencyAccumulator { - private final Set inputs = new HashSet<>(10); - private boolean overlap = false; - - private final InstructionValueConsumer valueConsumer = (instruction, value, mode, flags) -> { - Object valueObject = value; - if (isRegister(value)) { // Canonicalize registers - valueObject = asRegister(value); - } - if (!inputs.add(valueObject)) { - overlap = true; - } - }; - - public void start(LIRInstruction initial) { - inputs.clear(); - overlap = false; - initial.visitEachInput(valueConsumer); - initial.visitEachTemp(valueConsumer); - initial.visitEachAlive(valueConsumer); - } - - /** - * Adds the inputs of lir instruction to the accumulator and returns, true if there was any - * overlap of parameters. - * - * @param inst - * @return true if an overlap was found - */ - public boolean add(LIRInstruction inst) { - overlap = false; - inst.visitEachOutput(valueConsumer); - inst.visitEachTemp(valueConsumer); - inst.visitEachInput(valueConsumer); - inst.visitEachAlive(valueConsumer); - return overlap; - } - } - - @Override - public RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { - RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig; - return new SPARCHotSpotRegisterAllocationConfig(registerConfigNonNull, allocationRestrictedTo); - } - - @Override - public EconomicSet translateToCallerRegisters(EconomicSet calleeRegisters) { - EconomicSet callerRegisters = EconomicSet.create(Equivalence.IDENTITY, calleeRegisters.size()); - for (Register register : calleeRegisters) { - if (l0.number <= register.number && register.number <= l7.number) { - // do nothing - } else if (o0.number <= register.number && register.number <= o7.number) { - // do nothing - } else if (i0.number <= register.number && register.number <= i7.number) { - // translate input to output registers - callerRegisters.add(translateInputToOutputRegister(register)); - } else { - callerRegisters.add(register); - } - } - return callerRegisters; - } - - private Register translateInputToOutputRegister(Register register) { - assert i0.number <= register.number && register.number <= i7.number : "Not an input register " + register; - return getTarget().arch.getRegisters().get(o0.number + register.number - i0.number); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2012, 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import java.util.HashSet; -import java.util.Set; - -import org.graalvm.compiler.bytecode.BytecodeProvider; -import org.graalvm.compiler.core.sparc.SPARCAddressLowering; -import org.graalvm.compiler.core.sparc.SPARCSuitesCreator; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.graalvm.compiler.hotspot.HotSpotBackendFactory; -import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl; -import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotPlatformConfigurationProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins; -import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.meta.HotSpotRegisters; -import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotSnippetReflectionProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; -import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.graalvm.compiler.nodes.spi.LoweringProvider; -import org.graalvm.compiler.nodes.spi.PlatformConfigurationProvider; -import org.graalvm.compiler.nodes.spi.Replacements; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.common.AddressLoweringPhase; -import org.graalvm.compiler.phases.tiers.CompilerConfiguration; -import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.compiler.replacements.sparc.SPARCGraphBuilderPlugins; -import org.graalvm.compiler.serviceprovider.ServiceProvider; - -import jdk.vm.ci.code.Architecture; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; -import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotMetaAccessProvider; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.runtime.JVMCIBackend; -import jdk.vm.ci.sparc.SPARC; - -@ServiceProvider(HotSpotBackendFactory.class) -public class SPARCHotSpotBackendFactory extends HotSpotBackendFactory { - - @Override - public String getName() { - return "community"; - } - - @Override - public Class getArchitecture() { - return SPARC.class; - } - - @Override - public HotSpotBackend createBackend(HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, HotSpotJVMCIRuntime jvmciRuntime, HotSpotBackend host) { - assert host == null; - - OptionValues options = runtime.getOptions(); - GraalHotSpotVMConfig config = runtime.getVMConfig(); - JVMCIBackend jvmci = jvmciRuntime.getHostJVMCIBackend(); - HotSpotRegistersProvider registers = createRegisters(); - HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) jvmci.getMetaAccess(); - HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmci.getCodeCache(); - TargetDescription target = codeCache.getTarget(); - HotSpotConstantReflectionProvider constantReflection = (HotSpotConstantReflectionProvider) jvmci.getConstantReflection(); - HotSpotConstantFieldProvider constantFieldProvider = createConstantFieldProvider(config, metaAccess); - Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(config, codeCache.getRegisterConfig()); - HotSpotWordTypes wordTypes = createWordTypes(metaAccess, target); - HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes, nativeABICallerSaveRegisters); - HotSpotStampProvider stampProvider = createStampProvider(); - HotSpotPlatformConfigurationProvider platformConfigurationProvider = createConfigInfoProvider(config, metaAccess); - LoweringProvider lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, constantReflection, platformConfigurationProvider, target); - Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, platformConfigurationProvider); - HotSpotSnippetReflectionProvider snippetReflection = createSnippetReflection(runtime, constantReflection, wordTypes); - BytecodeProvider bytecodeProvider = createBytecodeProvider(metaAccess, snippetReflection); - HotSpotReplacementsImpl replacements = createReplacements(target, p, snippetReflection, bytecodeProvider); - Plugins plugins = createGraphBuilderPlugins(runtime, compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, snippetReflection, replacements, wordTypes, - runtime.getOptions(), target); - replacements.setGraphBuilderPlugins(plugins); - HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements); - HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers, - snippetReflection, wordTypes, plugins, platformConfigurationProvider); - replacements.setProviders(providers); - replacements.maybeInitializeEncoder(options); - - return createBackend(config, runtime, providers); - } - - protected Plugins createGraphBuilderPlugins(HotSpotGraalRuntimeProvider graalRuntime, - CompilerConfiguration compilerConfiguration, - GraalHotSpotVMConfig config, - HotSpotMetaAccessProvider metaAccess, - HotSpotConstantReflectionProvider constantReflection, - HotSpotForeignCallsProvider foreignCalls, - HotSpotSnippetReflectionProvider snippetReflection, - HotSpotReplacementsImpl replacements, - HotSpotWordTypes wordTypes, - OptionValues options, - TargetDescription target) { - Plugins plugins = HotSpotGraphBuilderPlugins.create( - graalRuntime, - compilerConfiguration, - config, - wordTypes, - metaAccess, - constantReflection, - snippetReflection, - foreignCalls, - replacements, - options, - target); - SPARCGraphBuilderPlugins.register(plugins, replacements, false); - return plugins; - } - - /** - * @param replacements - */ - protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins, - Replacements replacements) { - return new AddressLoweringHotSpotSuitesProvider(new SPARCSuitesCreator(compilerConfiguration, plugins), config, runtime, new AddressLoweringPhase(new SPARCAddressLowering())); - } - - protected SPARCHotSpotBackend createBackend(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { - return new SPARCHotSpotBackend(config, runtime, providers); - } - - protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls, - HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, PlatformConfigurationProvider platformConfig, TargetDescription target) { - return new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, platformConfig, target); - } - - protected HotSpotRegistersProvider createRegisters() { - return new HotSpotRegisters(SPARC.g2, SPARC.g6, SPARC.sp); - } - - @SuppressWarnings("unused") - private static Value[] createNativeABICallerSaveRegisters(GraalHotSpotVMConfig config, RegisterConfig regConfig) { - Set callerSavedRegisters = new HashSet<>(); - SPARC.fpusRegisters.addTo(callerSavedRegisters); - SPARC.fpudRegisters.addTo(callerSavedRegisters); - callerSavedRegisters.add(SPARC.g1); - callerSavedRegisters.add(SPARC.g4); - callerSavedRegisters.add(SPARC.g5); - Value[] nativeABICallerSaveRegisters = new Value[callerSavedRegisters.size()]; - int i = 0; - for (Register reg : callerSavedRegisters) { - nativeABICallerSaveRegisters[i] = reg.asValue(); - i++; - } - return nativeABICallerSaveRegisters; - } - - @Override - public String toString() { - return "SPARC"; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; -import org.graalvm.compiler.lir.sparc.SPARCMove; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.Value; - -@Opcode("CRUNTIME_CALL_EPILOGUE") -final class SPARCHotSpotCRuntimeCallEpilogueOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallEpilogueOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(11); - - private final int threadLastJavaSpOffset; - private final int threadLastJavaPcOffset; - private final int threadJavaFrameAnchorFlagsOffset; - private final Register thread; - @Use({REG, STACK}) protected Value threadTemp; - - SPARCHotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset, Register thread, Value threadTemp) { - super(TYPE, SIZE); - this.threadLastJavaSpOffset = threadLastJavaSpOffset; - this.threadLastJavaPcOffset = threadLastJavaPcOffset; - this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset; - this.thread = thread; - this.threadTemp = threadTemp; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - - // Restore the thread register when coming back from the runtime. - SPARCMove.move(crb, masm, thread.asValue(LIRKind.value(XWORD)), threadTemp, SPARCDelayedControlTransfer.DUMMY); - - // Reset last Java frame, last Java PC and flags. - masm.stx(g0, new SPARCAddress(thread, threadLastJavaSpOffset)); - masm.stx(g0, new SPARCAddress(thread, threadLastJavaPcOffset)); - masm.stw(g0, new SPARCAddress(thread, threadJavaFrameAnchorFlagsOffset)); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.STACK_BIAS; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; -import org.graalvm.compiler.lir.sparc.SPARCMove; -import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Value; - -@Opcode("CRUNTIME_CALL_PROLOGUE") -final class SPARCHotSpotCRuntimeCallPrologueOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallPrologueOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(10); - - private final int threadLastJavaSpOffset; - private final Register thread; - private final Register stackPointer; - @Def({REG, STACK}) protected Value threadTemp; - @Temp({REG}) protected AllocatableValue spScratch; - - SPARCHotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, Register stackPointer, Value threadTemp, AllocatableValue spScratch) { - super(TYPE, SIZE); - this.threadLastJavaSpOffset = threadLastJavaSpOffset; - this.thread = thread; - this.stackPointer = stackPointer; - this.threadTemp = threadTemp; - this.spScratch = spScratch; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // Save last Java frame. - Register scratchRegister = asRegister(spScratch); - masm.add(stackPointer, STACK_BIAS, scratchRegister); - masm.stx(scratchRegister, new SPARCAddress(thread, threadLastJavaSpOffset)); - - // Save the thread register when calling out to the runtime. - SPARCMove.move(crb, masm, threadTemp, thread.asValue(LIRKind.value(XWORD)), getDelayedControlTransfer()); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotCounterOp.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; -import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static jdk.vm.ci.code.ValueUtil.asRegister; - -import org.graalvm.compiler.asm.Assembler; -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.hotspot.HotSpotCounterOp; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.meta.Value; - -@Opcode("BenchMarkCounter") -public class SPARCHotSpotCounterOp extends HotSpotCounterOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class); - - private int[] counterPatchOffsets; - - public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) { - super(TYPE, name, group, increment, registers, config); - this.counterPatchOffsets = new int[1]; - } - - public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, GraalHotSpotVMConfig config) { - super(TYPE, names, groups, increments, registers, config); - this.counterPatchOffsets = new int[names.length]; - } - - @Override - public void emitCode(CompilationResultBuilder crb) { - SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; - TargetDescription target = crb.target; - - // address for counters array - SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.jvmciCountersThreadOffset); - try (ScratchRegister scratch = masm.getScratchRegister()) { - Register countersArrayReg = scratch.getRegister(); - - // load counters array - masm.ldx(countersArrayAddr, countersArrayReg); - IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm); - forEachCounter(emitter, target); - } - } - - private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) { - try (ScratchRegister scratch = masm.getScratchRegister()) { - Register counterReg = scratch.getRegister(); - // load counter value - masm.ldx(counterAddr, counterReg); - counterPatchOffsets[counterIndex] = masm.position(); - // increment counter - if (isJavaConstant(increment)) { - masm.add(counterReg, asInt(asJavaConstant(increment)), counterReg); - } else { - masm.add(counterReg, asRegister(increment), counterReg); - } - // store counter value - masm.stx(counterReg, counterAddr); - } - } - - /** - * Patches the increment value in the instruction emitted by the - * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is - * used if patching is needed after assembly. - * - * @param asm - * @param increment - */ - @Override - public void patchCounterIncrement(Assembler asm, int[] increment) { - for (int i = 0; i < increment.length; i++) { - int inst = counterPatchOffsets[i]; - ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]); - } - } - - public int[] getCounterPatchOffsets() { - return counterPatchOffsets; - } - - private class IncrementEmitter implements CounterProcedure { - private int lastDisplacement = 0; - private final Register countersArrayReg; - private final SPARCMacroAssembler masm; - - IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) { - super(); - this.countersArrayReg = countersArrayReg; - this.masm = masm; - } - - @Override - public void apply(int counterIndex, Value increment, int displacement) { - SPARCAddress counterAddr; - int relativeDisplacement = displacement - lastDisplacement; - if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction - counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement); - } else { - try (ScratchRegister scratch = masm.getScratchRegister()) { - Register tempOffsetRegister = scratch.getRegister(); - masm.setx(relativeDisplacement, tempOffsetRegister, false); - masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg); - } - lastDisplacement = displacement; - counterAddr = new SPARCAddress(countersArrayReg, 0); - } - emitIncrement(counterIndex, masm, counterAddr, increment); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2012, 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNCOMMON_TRAP; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall; - -import jdk.vm.ci.code.Register; - -/** - * Removes the current frame and tail calls the uncommon trap routine. - */ -@Opcode("DEOPT_CALLER") -final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeCallerOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(32); - - protected SPARCHotSpotDeoptimizeCallerOp() { - super(TYPE, SIZE); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - leaveFrame(crb); - - // SPARCHotSpotBackend backend = (SPARCHotSpotBackend) - // HotSpotGraalRuntime.runtime().getBackend(); - // final boolean isStub = true; - // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub); - // frameContext.enter(crb); - - try (ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNCOMMON_TRAP)); - } - - // frameContext.leave(crb); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotDeoptimizeWithExceptionCallerOp.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARC; - -/** - * Removes the current frame and tail calls the uncommon trap routine. - */ -@Opcode("DEOPT_WITH_EXCEPTION_IN_CALLER") -final class SPARCHotSpotDeoptimizeWithExceptionCallerOp extends SPARCHotSpotEpilogueOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeWithExceptionCallerOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(32); - - private final GraalHotSpotVMConfig config; - private final Register thread; - @Use(OperandFlag.REG) private Value exception; - - protected SPARCHotSpotDeoptimizeWithExceptionCallerOp(GraalHotSpotVMConfig config, Value exception, Register thread) { - super(TYPE, SIZE); - this.config = config; - this.exception = exception; - this.thread = thread; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register exc = asRegister(exception); - - // Save exception oop in TLS - masm.stx(exc, new SPARCAddress(thread, config.threadExceptionOopOffset)); - // Store original return address in TLS - masm.stx(SPARC.i7, new SPARCAddress(thread, config.threadExceptionPcOffset)); - - leaveFrame(crb); - - try (SPARCMacroAssembler.ScratchRegister sc = masm.getScratchRegister()) { - Register scratch = sc.getRegister(); - SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK_WITH_EXCEPTION_IN_TLS)); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotEpilogueOp.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCBlockEndOp; - -/** - * Superclass for operations that leave a method's frame. - */ -abstract class SPARCHotSpotEpilogueOp extends SPARCBlockEndOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotEpilogueOp.class); - - protected SPARCHotSpotEpilogueOp(LIRInstructionClass c, SizeEstimate size) { - super(c, size); - } - - protected void leaveFrame(CompilationResultBuilder crb) { - crb.frameContext.leave(crb); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2013, 2019, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.hotspot.HotSpotCallingConventionType.NativeCall; -import static jdk.vm.ci.meta.Value.ILLEGAL; -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i1; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o1; -import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER; -import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; -import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.JUMP_ADDRESS; -import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_ALL_CALLER_SAVE_REGISTERS; -import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Reexecutability.NOT_REEXECUTABLE; -import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.LEAF_NO_VZERO; -import static org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions.UPDATE_BYTES_CRC32C; -import static org.graalvm.compiler.hotspot.replacements.CRC32Substitutions.UPDATE_BYTES_CRC32; -import static jdk.internal.vm.compiler.word.LocationIdentity.any; - -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; -import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.word.WordTypes; - -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.CodeCacheProvider; -import jdk.vm.ci.code.RegisterValue; -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.Value; - -public class SPARCHotSpotForeignCallsProvider extends HotSpotHostForeignCallsProvider { - - private final Value[] nativeABICallerSaveRegisters; - - public SPARCHotSpotForeignCallsProvider(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, CodeCacheProvider codeCache, - WordTypes wordTypes, Value[] nativeABICallerSaveRegisters) { - super(jvmciRuntime, runtime, metaAccess, codeCache, wordTypes); - this.nativeABICallerSaveRegisters = nativeABICallerSaveRegisters; - } - - @Override - public void initialize(HotSpotProviders providers, OptionValues options) { - GraalHotSpotVMConfig config = runtime.getVMConfig(); - TargetDescription target = providers.getCodeCache().getTarget(); - PlatformKind word = target.arch.getWordKind(); - - // The calling convention for the exception handler stub is (only?) defined in - // TemplateInterpreterGenerator::generate_throw_exception() - // in templateInterpreter_sparc.cpp around line 1925 - RegisterValue outgoingException = o0.asValue(LIRKind.fromJavaKind(target.arch, JavaKind.Object)); - RegisterValue outgoingExceptionPc = o1.asValue(LIRKind.value(word)); - RegisterValue incomingException = i0.asValue(LIRKind.fromJavaKind(target.arch, JavaKind.Object)); - RegisterValue incomingExceptionPc = i1.asValue(LIRKind.value(word)); - CallingConvention outgoingExceptionCc = new CallingConvention(0, ILLEGAL, outgoingException, outgoingExceptionPc); - CallingConvention incomingExceptionCc = new CallingConvention(0, ILLEGAL, incomingException, incomingExceptionPc); - register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, DESTROYS_ALL_CALLER_SAVE_REGISTERS, LEAF_NO_VZERO, NOT_REEXECUTABLE, outgoingExceptionCc, - incomingExceptionCc, - any())); - register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, DESTROYS_ALL_CALLER_SAVE_REGISTERS, LEAF_NO_VZERO, NOT_REEXECUTABLE, outgoingExceptionCc, - incomingExceptionCc, any())); - - if (config.useCRC32Intrinsics) { - // This stub does callee saving - registerForeignCall(UPDATE_BYTES_CRC32, config.updateBytesCRC32Stub, NativeCall, LEAF_NO_VZERO, NOT_REEXECUTABLE, any()); - } - if (config.useCRC32CIntrinsics) { - registerForeignCall(UPDATE_BYTES_CRC32C, config.updateBytesCRC32C, NativeCall, LEAF_NO_VZERO, NOT_REEXECUTABLE, any()); - } - - super.initialize(providers, options); - } - - @Override - public Value[] getNativeABICallerSaveRegisters() { - return nativeABICallerSaveRegisters; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARC.l7; -import static jdk.vm.ci.sparc.SPARC.sp; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; - -/** - * Sets up the arguments for an exception handler in the callers frame, removes the current frame - * and jumps to the handler. - */ -@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER") -final class SPARCHotSpotJumpToExceptionHandlerInCallerOp extends SPARCHotSpotEpilogueOp { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerInCallerOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(5); - - @Use(REG) AllocatableValue handlerInCallerPc; - @Use(REG) AllocatableValue exception; - @Use(REG) AllocatableValue exceptionPc; - private final Register thread; - private final int isMethodHandleReturnOffset; - - SPARCHotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) { - super(TYPE, SIZE); - this.handlerInCallerPc = handlerInCallerPc; - this.exception = exception; - this.exceptionPc = exceptionPc; - this.isMethodHandleReturnOffset = isMethodHandleReturnOffset; - this.thread = thread; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // Restore SP from L7 if the exception PC is a method handle call site. - SPARCAddress dst = new SPARCAddress(thread, isMethodHandleReturnOffset); - try (ScratchRegister scratch = masm.getScratchRegister()) { - Register scratchReg = scratch.getRegister(); - masm.lduw(dst, scratchReg); - masm.cmp(scratchReg, scratchReg); - masm.movcc(ConditionFlag.NotZero, CC.Icc, l7, sp); - } - masm.jmpl(asRegister(handlerInCallerPc), 0, g0); - leaveFrame(crb); // Delay slot - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerOp.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.sparc.SPARCKind; - -/** - * Jumps to the exception handler specified by {@link #address} and leaves the current window. It - * does not modify the i7 register, as the exception handler stub expects the throwing pc in it. - *

- * See also: - *

  • Runtime1::generate_handle_exception c1_Runtime1_sparc.cpp - *
  • SharedRuntime::generate_deopt_blob at exception_in_tls_offset (sharedRuntime_sparc.cpp) - */ -@Opcode("JUMP_TO_EXCEPTION_HANDLER") -final class SPARCHotSpotJumpToExceptionHandlerOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(2); - - @Use(REG) AllocatableValue address; - - SPARCHotSpotJumpToExceptionHandlerOp(AllocatableValue address) { - super(TYPE, SIZE); - this.address = address; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register addrRegister = asRegister(address, SPARCKind.XWORD); - masm.jmp(addrRegister); - masm.restoreWindow(); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Copyright (c) 2013, 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; -import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; -import static org.graalvm.compiler.lir.StandardOp.ZapRegistersOp; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.calc.Condition; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.core.common.spi.LIRKindTool; -import org.graalvm.compiler.core.sparc.SPARCArithmeticLIRGenerator; -import org.graalvm.compiler.core.sparc.SPARCLIRGenerator; -import org.graalvm.compiler.core.sparc.SPARCLIRKindTool; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; -import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.HotSpotLockStack; -import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.hotspot.stubs.Stub; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstruction; -import org.graalvm.compiler.lir.LabelRef; -import org.graalvm.compiler.lir.SwitchStrategy; -import org.graalvm.compiler.lir.Variable; -import org.graalvm.compiler.lir.VirtualStackSlot; -import org.graalvm.compiler.lir.gen.LIRGenerationResult; -import org.graalvm.compiler.lir.sparc.SPARCAddressValue; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.StrategySwitchOp; -import org.graalvm.compiler.lir.sparc.SPARCFrameMapBuilder; -import org.graalvm.compiler.lir.sparc.SPARCImmediateAddressValue; -import org.graalvm.compiler.lir.sparc.SPARCMove.CompareAndSwapOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.NullCheckOp; -import org.graalvm.compiler.lir.sparc.SPARCMove.StoreOp; -import org.graalvm.compiler.lir.sparc.SPARCPrefetchOp; -import org.graalvm.compiler.lir.sparc.SPARCSaveRegistersOp; - -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterValue; -import jdk.vm.ci.code.StackSlot; -import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.DeoptimizationAction; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.SpeculationLog; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.meta.ValueKind; -import jdk.vm.ci.sparc.SPARC; -import jdk.vm.ci.sparc.SPARCKind; - -public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator { - - final GraalHotSpotVMConfig config; - private HotSpotDebugInfoBuilder debugInfoBuilder; - - public SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { - this(providers, config, lirGenRes, new ConstantTableBaseProvider()); - } - - private SPARCHotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) { - this(new SPARCLIRKindTool(), new SPARCArithmeticLIRGenerator(), new SPARCHotSpotMoveFactory(constantTableBaseProvider), providers, config, lirGenRes, constantTableBaseProvider); - } - - public SPARCHotSpotLIRGenerator(LIRKindTool lirKindTool, SPARCArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, - LIRGenerationResult lirGenRes, ConstantTableBaseProvider constantTableBaseProvider) { - super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes, constantTableBaseProvider); - assert config.basicLockSize == 8; - this.config = config; - } - - @Override - public HotSpotProviders getProviders() { - return (HotSpotProviders) super.getProviders(); - } - - /** - * The slot reserved for storing the original return address when a frame is marked for - * deoptimization. The return address slot in the callee is overwritten with the address of a - * deoptimization stub. - */ - private StackSlot deoptimizationRescueSlot; - - /** - * Value where the address for safepoint poll is kept. - */ - private AllocatableValue safepointAddressValue; - - @Override - public VirtualStackSlot getLockSlot(int lockDepth) { - return getLockStack().makeLockSlot(lockDepth); - } - - private HotSpotLockStack getLockStack() { - assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; - return debugInfoBuilder.lockStack(); - } - - @Override - public boolean needOnlyOopMaps() { - // Stubs only need oop maps - return getStub() != null; - } - - public Stub getStub() { - return getResult().getStub(); - } - - @Override - public HotSpotLIRGenerationResult getResult() { - return ((HotSpotLIRGenerationResult) super.getResult()); - } - - @Override - public void beforeRegisterAllocation() { - super.beforeRegisterAllocation(); - boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); - if (hasDebugInfo) { - getResult().setDeoptimizationRescueSlot(((SPARCFrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); - } - - getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); - } - - @Override - public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { - HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; - Variable result; - LIRFrameState debugInfo = null; - if (hotspotLinkage.needsDebugInfo()) { - debugInfo = state; - assert debugInfo != null || getStub() != null; - } - - if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) { - HotSpotRegistersProvider registers = getProviders().getRegisters(); - Register thread = registers.getThreadRegister(); - Value threadTemp = newVariable(LIRKind.value(SPARCKind.XWORD)); - Register stackPointer = registers.getStackPointerRegister(); - Variable spScratch = newVariable(LIRKind.value(target().arch.getWordKind())); - append(new SPARCHotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread, stackPointer, threadTemp, spScratch)); - result = super.emitForeignCall(hotspotLinkage, debugInfo, args); - append(new SPARCHotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadJavaFrameAnchorFlagsOffset(), thread, threadTemp)); - } else { - result = super.emitForeignCall(hotspotLinkage, debugInfo, args); - } - - return result; - } - - @Override - public void emitReturn(JavaKind javaKind, Value input) { - AllocatableValue operand = Value.ILLEGAL; - if (input != null) { - operand = resultOperandFor(javaKind, input.getValueKind()); - emitMove(operand, input); - } - Register thread = getProviders().getRegisters().getThreadRegister(); - append(new SPARCHotSpotReturnOp(operand, getStub() != null, config, thread, getSafepointAddressValue(), getResult().requiresReservedStackAccessCheck())); - } - - @Override - public void emitTailcall(Value[] args, Value address) { - throw GraalError.unimplemented(); - } - - @Override - public void emitUnwind(Value exception) { - ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); - CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); - assert linkageCc.getArgumentCount() == 2; - RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0); - emitMove(exceptionParameter, exception); - append(new SPARCHotSpotUnwindOp(exceptionParameter)); - } - - private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { - moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); - moveValueToThread(speculation, config.pendingFailedSpeculationOffset); - } - - private void moveValueToThread(Value v, int offset) { - LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); - RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); - SPARCAddressValue pendingDeoptAddress = new SPARCImmediateAddressValue(wordKind, thread, offset); - append(new StoreOp(v.getPlatformKind(), pendingDeoptAddress, load(v), null)); - } - - @Override - public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { - moveDeoptValuesToThread(actionAndReason, speculation); - append(new SPARCDeoptimizeOp(state, target().arch.getWordKind())); - } - - @Override - public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { - Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); - Value speculation = emitJavaConstant(getMetaAccess().encodeSpeculation(SpeculationLog.NO_SPECULATION)); - moveDeoptValuesToThread(actionAndReason, speculation); - append(new SPARCHotSpotDeoptimizeCallerOp()); - } - - @Override - public void emitDeoptimizeWithExceptionInCaller(Value exception) { - Register thread = getProviders().getRegisters().getThreadRegister(); - append(new SPARCHotSpotDeoptimizeWithExceptionCallerOp(config, exception, thread)); - } - - @Override - public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) { - ValueKind kind = newValue.getValueKind(); - assert kind.equals(expectedValue.getValueKind()); - SPARCKind memKind = (SPARCKind) kind.getPlatformKind(); - Variable result = newVariable(newValue.getValueKind()); - append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue))); - return emitConditionalMove(memKind, expectedValue, result, Condition.EQ, true, trueValue, falseValue); - } - - @Override - public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) { - ValueKind kind = newValue.getValueKind(); - assert kind.equals(expectedValue.getValueKind()); - Variable result = newVariable(newValue.getValueKind()); - append(new CompareAndSwapOp(result, asAllocatable(address), asAllocatable(expectedValue), asAllocatable(newValue))); - return result; - } - - @Override - public void emitPrefetchAllocate(Value address) { - SPARCAddressValue addr = asAddressValue(address); - append(new SPARCPrefetchOp(addr, SPARCAssembler.Fcn.SeveralWritesAndPossiblyReads)); - } - - public StackSlot getDeoptimizationRescueSlot() { - return deoptimizationRescueSlot; - } - - @Override - public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, - double trueDestinationProbability) { - Value localX = x; - Value localY = y; - if (localX instanceof HotSpotObjectConstant) { - localX = load(localX); - } - if (localY instanceof HotSpotObjectConstant) { - localY = load(localY); - } - super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); - } - - @Override - protected boolean emitCompare(SPARCKind cmpKind, Value a, Value b) { - Value localA = a; - Value localB = b; - if (isConstantValue(a)) { - Constant c = asConstant(a); - if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { - localA = SPARC.g0.asValue(LIRKind.value(WORD)); - } else if (c instanceof HotSpotObjectConstant) { - localA = load(localA); - } - } - if (isConstantValue(b)) { - Constant c = asConstant(b); - if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { - localB = SPARC.g0.asValue(LIRKind.value(WORD)); - } else if (c instanceof HotSpotObjectConstant) { - localB = load(localB); - } - } - return super.emitCompare(cmpKind, localA, localB); - } - - @Override - public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { - LIRKind inputKind = pointer.getValueKind(LIRKind.class); - assert inputKind.getPlatformKind() == XWORD : inputKind; - if (inputKind.isReference(0)) { - // oop - Variable result = newVariable(LIRKind.compressedReference(WORD)); - append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); - return result; - } else { - // metaspace pointer - Variable result = newVariable(LIRKind.value(WORD)); - AllocatableValue base = Value.ILLEGAL; - if (encoding.hasBase()) { - base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase())); - } - append(new SPARCHotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); - return result; - } - } - - @Override - public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { - LIRKind inputKind = pointer.getValueKind(LIRKind.class); - assert inputKind.getPlatformKind() == WORD; - if (inputKind.isReference(0)) { - // oop - Variable result = newVariable(LIRKind.reference(XWORD)); - append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); - return result; - } else { - // metaspace pointer - Variable result = newVariable(LIRKind.value(XWORD)); - AllocatableValue base = Value.ILLEGAL; - if (encoding.hasBase()) { - base = emitLoadConstant(LIRKind.value(XWORD), JavaConstant.forLong(encoding.getBase())); - } - append(new SPARCHotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); - return result; - } - } - - /** - * @param savedRegisters the registers saved by this operation which may be subject to pruning - * @param savedRegisterLocations the slots to which the registers are saved - */ - protected SPARCSaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations) { - SPARCSaveRegistersOp save = new SPARCSaveRegistersOp(savedRegisters, savedRegisterLocations); - append(save); - return save; - } - - @Override - public void emitNullCheck(Value address, LIRFrameState state) { - PlatformKind kind = address.getPlatformKind(); - if (kind == WORD) { - CompressEncoding encoding = config.getOopEncoding(); - Value uncompressed = emitUncompress(address, encoding, false); - append(new NullCheckOp(asAddressValue(uncompressed), state)); - } else { - super.emitNullCheck(address, state); - } - } - - @Override - public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { - if (BenchmarkCounters.enabled) { - return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config); - } - throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); - } - - @Override - public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { - if (BenchmarkCounters.enabled) { - return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config); - } - throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); - } - - public AllocatableValue getSafepointAddressValue() { - if (this.safepointAddressValue == null) { - this.safepointAddressValue = SPARCHotSpotSafepointOp.getSafepointAddressValue(this); - } - return this.safepointAddressValue; - } - - @Override - protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) { - return new SPARCHotSpotStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue); - } - - public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { - this.debugInfoBuilder = debugInfoBuilder; - } - - @Override - public ZapRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { - throw GraalError.unimplemented(); - } - - @Override - public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { - throw GraalError.unimplemented(); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i1; -import static jdk.vm.ci.sparc.SPARC.i2; -import static jdk.vm.ci.sparc.SPARC.i3; -import static jdk.vm.ci.sparc.SPARC.i4; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o1; -import static jdk.vm.ci.sparc.SPARC.o2; -import static jdk.vm.ci.sparc.SPARC.o3; -import static jdk.vm.ci.sparc.SPARC.o4; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; - -/** - * Pops the current frame off the stack. - */ -@Opcode("LEAVE_CURRENT_STACK_FRAME") -final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveCurrentStackFrameOp.class); - - SPARCHotSpotLeaveCurrentStackFrameOp() { - super(TYPE); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // Save O registers over restore. - masm.mov(o0, i0); - masm.mov(o1, i1); - masm.mov(o2, i2); - masm.mov(o3, i3); - masm.mov(o4, i4); - - crb.frameContext.leave(crb); - } - - @Override - public boolean leavesRegisterWindow() { - return true; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2014, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i1; -import static jdk.vm.ci.sparc.SPARC.i2; -import static jdk.vm.ci.sparc.SPARC.i3; -import static jdk.vm.ci.sparc.SPARC.i4; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o1; -import static jdk.vm.ci.sparc.SPARC.o2; -import static jdk.vm.ci.sparc.SPARC.o3; -import static jdk.vm.ci.sparc.SPARC.o4; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; - -/** - * Pops the current frame off the stack including the return address. - */ -@Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME") -final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCLIRInstruction { - - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveDeoptimizedStackFrameOp.class); - - protected SPARCHotSpotLeaveDeoptimizedStackFrameOp() { - super(TYPE); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // Save O registers over restore. - masm.mov(o0, i0); - masm.mov(o1, i1); - masm.mov(o2, i2); - masm.mov(o3, i3); - masm.mov(o4, i4); - - masm.restoreWindow(); - } - - @Override - public boolean leavesRegisterWindow() { - return true; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLoweringProvider.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2013, 2020, 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 org.graalvm.compiler.hotspot.sparc; - -import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; -import org.graalvm.compiler.core.sparc.SparcLoweringProviderMixin; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; -import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider; -import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; -import org.graalvm.compiler.nodes.calc.FloatConvertNode; -import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.nodes.spi.PlatformConfigurationProvider; - -import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; - -public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider implements SparcLoweringProviderMixin { - - public SPARCHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers, - HotSpotConstantReflectionProvider constantReflection, PlatformConfigurationProvider platformConfig, TargetDescription target) { - super(runtime, metaAccess, foreignCalls, registers, constantReflection, platformConfig, target); - } - - @Override - public void lower(Node n, LoweringTool tool) { - if (n instanceof FloatConvertNode) { - // FloatConvertNodes are handled in SPARCLIRGenerator.emitConvert - } else { - super.lower(n, tool); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2013, 2019, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPR; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_nz; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.RCondition.Rc_z; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; -import static org.graalvm.compiler.lir.sparc.SPARCMove.loadFromConstantTable; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.StandardOp.LoadConstantOp; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; -import org.graalvm.compiler.lir.sparc.SPARCTailDelayedLIRInstruction; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.ValueUtil; -import jdk.vm.ci.hotspot.HotSpotConstant; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.sparc.SPARC; - -public class SPARCHotSpotMove { - - public static class LoadHotSpotObjectConstantInline extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction, LoadConstantOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantInline.class); - - public static final SizeEstimate SIZE = SizeEstimate.create(8); - private HotSpotConstant constant; - @Def({REG, STACK}) AllocatableValue result; - - public LoadHotSpotObjectConstantInline(HotSpotConstant constant, AllocatableValue result) { - super(TYPE, SIZE); - this.constant = constant; - this.result = result; - } - - @Override - protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - crb.recordInlineDataInCode(constant); - if (constant.isCompressed()) { - masm.setw(0, asRegister(result), true); - } else { - masm.setx(0, asRegister(result), true); - } - } - - @Override - public AllocatableValue getResult() { - return result; - } - - @Override - public Constant getConstant() { - return constant; - } - } - - public static class LoadHotSpotObjectConstantFromTable extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(LoadHotSpotObjectConstantFromTable.class); - - public static final SizeEstimate SIZE = SizeEstimate.create(2, 8); - private final HotSpotConstant constant; - @Use({REG}) private AllocatableValue constantTableBase; - @Def({REG, STACK}) AllocatableValue result; - - public LoadHotSpotObjectConstantFromTable(HotSpotConstant constant, AllocatableValue result, AllocatableValue constantTableBase) { - super(TYPE, SIZE); - this.constant = constant; - this.result = result; - this.constantTableBase = constantTableBase; - } - - @Override - protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (ScratchRegister scratch = masm.getScratchRegister()) { - boolean isStack = ValueUtil.isStackSlot(result); - Register register; - if (isStack) { - register = scratch.getRegister(); - } else { - register = asRegister(result); - } - int bytes = loadFromConstantTable(crb, masm, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY); - if (isStack) { - masm.st(register, (SPARCAddress) crb.asAddress(result), bytes); - } - } - } - } - - public static final class CompressPointer extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompressPointer.class); - public static final SizeEstimate SIZE = SizeEstimate.create(5); - - private final CompressEncoding encoding; - private final boolean nonNull; - - @Def({REG}) protected AllocatableValue result; - @Use({REG}) protected AllocatableValue input; - @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; - - public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { - super(TYPE, SIZE); - this.result = result; - this.input = input; - this.baseRegister = baseRegister; - this.encoding = encoding; - this.nonNull = nonNull; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register inputRegister = asRegister(input); - Register resReg = asRegister(result); - if (encoding.hasBase()) { - Register baseReg = asRegister(baseRegister); - if (!nonNull) { - Label done = new Label(); - if (inputRegister.equals(resReg)) { - BPR.emit(masm, Rc_nz, ANNUL, PREDICT_TAKEN, inputRegister, done); - masm.sub(inputRegister, baseReg, resReg); - masm.bind(done); - if (encoding.getShift() != 0) { - masm.srlx(resReg, encoding.getShift(), resReg); - } - } else { - BPR.emit(masm, Rc_z, NOT_ANNUL, PREDICT_NOT_TAKEN, inputRegister, done); - masm.mov(SPARC.g0, resReg); - masm.sub(inputRegister, baseReg, resReg); - if (encoding.getShift() != 0) { - masm.srlx(resReg, encoding.getShift(), resReg); - } - masm.bind(done); - } - } else { - masm.sub(inputRegister, baseReg, resReg); - if (encoding.getShift() != 0) { - masm.srlx(resReg, encoding.getShift(), resReg); - } - } - } else { - if (encoding.getShift() != 0) { - masm.srlx(inputRegister, encoding.getShift(), resReg); - } - } - } - } - - public static final class UncompressPointer extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(UncompressPointer.class); - public static final SizeEstimate SIZE = SizeEstimate.create(4); - - private final CompressEncoding encoding; - private final boolean nonNull; - - @Def({REG}) protected AllocatableValue result; - @Use({REG}) protected AllocatableValue input; - @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister; - - public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) { - super(TYPE, SIZE); - this.result = result; - this.input = input; - this.baseRegister = baseRegister; - this.encoding = encoding; - this.nonNull = nonNull; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register inputRegister = asRegister(input); - Register resReg = asRegister(result); - Register baseReg = encoding.hasBase() ? asRegister(baseRegister) : null; - emitUncompressCode(masm, inputRegister, resReg, baseReg, encoding.getShift(), nonNull); - } - - public static void emitUncompressCode(SPARCMacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) { - Register secondaryInput; - if (shift != 0) { - masm.sllx(inputRegister, shift, resReg); - secondaryInput = resReg; - } else { - secondaryInput = inputRegister; - } - - if (baseReg != null) { - if (nonNull) { - masm.add(secondaryInput, baseReg, resReg); - } else { - Label done = new Label(); - BPR.emit(masm, Rc_nz, ANNUL, PREDICT_TAKEN, secondaryInput, done); - masm.add(baseReg, secondaryInput, resReg); - masm.bind(done); - } - } - } - } - -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMoveFactory.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.hotspot.HotSpotCompressedNullConstant.COMPRESSED_NULL; -import static jdk.vm.ci.meta.JavaConstant.INT_0; -import static jdk.vm.ci.meta.JavaConstant.LONG_0; - -import org.graalvm.compiler.core.sparc.SPARCLIRGenerator.ConstantTableBaseProvider; -import org.graalvm.compiler.core.sparc.SPARCMoveFactory; -import org.graalvm.compiler.lir.LIRInstruction; - -import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; -import jdk.vm.ci.hotspot.HotSpotConstant; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.hotspot.HotSpotObjectConstant; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; - -public class SPARCHotSpotMoveFactory extends SPARCMoveFactory { - - public SPARCHotSpotMoveFactory(ConstantTableBaseProvider constantTableBaseProvider) { - super(constantTableBaseProvider); - } - - @Override - public boolean canInlineConstant(Constant c) { - if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { - return true; - } else if (c instanceof HotSpotObjectConstant || c instanceof HotSpotMetaspaceConstant) { - return false; - } else { - return super.canInlineConstant(c); - } - } - - @Override - public LIRInstruction createLoad(AllocatableValue dst, Constant src) { - Constant usedSource; - if (COMPRESSED_NULL.equals(src)) { - usedSource = INT_0; - } else if (src instanceof HotSpotObjectConstant && ((HotSpotObjectConstant) src).isNull()) { - usedSource = LONG_0; - } else { - usedSource = src; - } - if (usedSource instanceof HotSpotConstant) { - HotSpotConstant constant = (HotSpotConstant) usedSource; - if (constant.isCompressed()) { - return new SPARCHotSpotMove.LoadHotSpotObjectConstantInline(constant, dst); - } else { - return new SPARCHotSpotMove.LoadHotSpotObjectConstantFromTable(constant, dst, constantTableBaseProvider.getConstantTableBase()); - } - } else { - return super.createLoad(dst, usedSource); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARC.g5; -import static jdk.vm.ci.sparc.SPARC.o7; -import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER_IN_CALLER; - -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.core.gen.DebugInfoBuilder; -import org.graalvm.compiler.core.sparc.SPARCNodeLIRBuilder; -import org.graalvm.compiler.core.sparc.SPARCNodeMatchRules; -import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; -import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; -import org.graalvm.compiler.hotspot.HotSpotLockStack; -import org.graalvm.compiler.hotspot.HotSpotNodeLIRBuilder; -import org.graalvm.compiler.hotspot.nodes.HotSpotDirectCallTargetNode; -import org.graalvm.compiler.hotspot.nodes.HotSpotIndirectCallTargetNode; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.Variable; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import org.graalvm.compiler.lir.sparc.SPARCBreakpointOp; -import org.graalvm.compiler.nodes.BreakpointNode; -import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; -import org.graalvm.compiler.nodes.DirectCallTargetNode; -import org.graalvm.compiler.nodes.FullInfopointNode; -import org.graalvm.compiler.nodes.IndirectCallTargetNode; -import org.graalvm.compiler.nodes.NodeView; -import org.graalvm.compiler.nodes.SafepointNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.spi.NodeValueMap; - -import jdk.vm.ci.code.BytecodeFrame; -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterValue; -import jdk.vm.ci.hotspot.HotSpotCallingConventionType; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.JavaType; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARCKind; - -public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements HotSpotNodeLIRBuilder { - - public SPARCHotSpotNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen, SPARCNodeMatchRules nodeMatchRules) { - super(graph, lirGen, nodeMatchRules); - assert gen instanceof SPARCHotSpotLIRGenerator; - assert getDebugInfoBuilder() instanceof HotSpotDebugInfoBuilder; - ((SPARCHotSpotLIRGenerator) gen).setDebugInfoBuilder(((HotSpotDebugInfoBuilder) getDebugInfoBuilder())); - } - - @Override - protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) { - HotSpotLockStack lockStack = new HotSpotLockStack(gen.getResult().getFrameMapBuilder(), LIRKind.value(SPARCKind.XWORD)); - return new HotSpotDebugInfoBuilder(nodeValueMap, lockStack, (HotSpotLIRGenerator) gen); - } - - private SPARCHotSpotLIRGenerator getGen() { - return (SPARCHotSpotLIRGenerator) gen; - } - - @Override - public void visitSafepointNode(SafepointNode i) { - LIRFrameState info = state(i); - Register thread = getGen().getProviders().getRegisters().getThreadRegister(); - append(new SPARCHotSpotSafepointOp(info, getGen().config, thread, gen)); - } - - @Override - protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - InvokeKind invokeKind = ((HotSpotDirectCallTargetNode) callTarget).invokeKind(); - if (invokeKind.isIndirect()) { - append(new SPARCHotspotDirectVirtualCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); - } else { - assert invokeKind.isDirect(); - HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); - assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method."; - append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config)); - } - } - - @Override - protected void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState) { - Value metaspaceMethodSrc = operand(((HotSpotIndirectCallTargetNode) callTarget).metaspaceMethod()); - AllocatableValue metaspaceMethod = g5.asValue(metaspaceMethodSrc.getValueKind()); - gen.emitMove(metaspaceMethod, metaspaceMethodSrc); - - Value targetAddressSrc = operand(callTarget.computedAddress()); - AllocatableValue targetAddress = o7.asValue(targetAddressSrc.getValueKind()); - gen.emitMove(targetAddress, targetAddressSrc); - append(new SPARCIndirectCallOp(callTarget.targetMethod(), result, parameters, temps, metaspaceMethod, targetAddress, callState, getGen().config)); - } - - @Override - public void emitPatchReturnAddress(ValueNode address) { - append(new SPARCHotSpotPatchReturnAddressOp(gen.load(operand(address)))); - } - - @Override - public void emitJumpToExceptionHandler(ValueNode address) { - append(new SPARCHotSpotJumpToExceptionHandlerOp(gen.load(operand(address)))); - } - - @Override - public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) { - Variable handler = gen.load(operand(handlerInCallerPc)); - ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER); - CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); - assert linkageCc.getArgumentCount() == 2; - RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0); - RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1); - gen.emitMove(exceptionFixed, operand(exception)); - gen.emitMove(exceptionPcFixed, operand(exceptionPc)); - Register thread = getGen().getProviders().getRegisters().getThreadRegister(); - SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed, getGen().config.threadIsMethodHandleReturnOffset, - thread); - append(op); - } - - @Override - protected void emitPrologue(StructuredGraph graph) { - super.emitPrologue(graph); - SPARCHotSpotSafepointOp.emitPrologue(this, getGen()); - } - - @Override - public void visitFullInfopointNode(FullInfopointNode i) { - if (i.getState() != null && i.getState().bci == BytecodeFrame.AFTER_BCI) { - i.getDebug().log("Ignoring InfopointNode for AFTER_BCI"); - } else { - super.visitFullInfopointNode(i); - } - } - - @Override - public void visitBreakpointNode(BreakpointNode node) { - JavaType[] sig = new JavaType[node.arguments().size()]; - for (int i = 0; i < sig.length; i++) { - sig[i] = node.arguments().get(i).stamp(NodeView.DEFAULT).javaType(gen.getMetaAccess()); - } - - Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments()); - append(new SPARCBreakpointOp(parameters)); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.i7; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; - -/** - * Patch the return address of the current frame. - */ -@Opcode("PATCH_RETURN") -final class SPARCHotSpotPatchReturnAddressOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotPatchReturnAddressOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(1); - - @Use(REG) AllocatableValue address; - - SPARCHotSpotPatchReturnAddressOp(AllocatableValue address) { - super(TYPE, SIZE); - this.address = address; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register addrRegister = asRegister(address, XWORD); - masm.sub(addrRegister, SPARCAssembler.PC_RETURN_OFFSET, i7); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i1; -import static jdk.vm.ci.sparc.SPARC.i2; -import static jdk.vm.ci.sparc.SPARC.i3; -import static jdk.vm.ci.sparc.SPARC.i4; -import static jdk.vm.ci.sparc.SPARC.i7; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o1; -import static jdk.vm.ci.sparc.SPARC.o2; -import static jdk.vm.ci.sparc.SPARC.o3; -import static jdk.vm.ci.sparc.SPARC.o4; -import static jdk.vm.ci.sparc.SPARC.o5; -import static jdk.vm.ci.sparc.SPARC.sp; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; - -/** - * Pushes an interpreter frame to the stack. - */ -@Opcode("PUSH_INTERPRETER_FRAME") -final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotPushInterpreterFrameOp.class); - - @Alive(REG) AllocatableValue frameSize; - @Alive(REG) AllocatableValue framePc; - @Alive(REG) AllocatableValue senderSp; - @Alive(REG) AllocatableValue initialInfo; - - SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) { - super(TYPE); - this.frameSize = frameSize; - this.framePc = framePc; - this.senderSp = senderSp; - this.initialInfo = initialInfo; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - final Register frameSizeRegister = asRegister(frameSize); - final Register framePcRegister = asRegister(framePc); - final Register senderSpRegister = asRegister(senderSp); - - // Save sender SP to O5_savedSP. - masm.mov(senderSpRegister, o5); - - masm.neg(frameSizeRegister); - masm.save(sp, frameSizeRegister, sp); - - masm.mov(i0, o0); - masm.mov(i1, o1); - masm.mov(i2, o2); - masm.mov(i3, o3); - masm.mov(i4, o4); - - // NOTE: Don't touch I5 as it contains valuable saved SP! - - // Move frame's new PC into i7 - masm.mov(framePcRegister, i7); - } - - @Override - public boolean leavesRegisterWindow() { - return true; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotRegisterAllocationConfig.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARC.d32; -import static jdk.vm.ci.sparc.SPARC.d34; -import static jdk.vm.ci.sparc.SPARC.d36; -import static jdk.vm.ci.sparc.SPARC.d38; -import static jdk.vm.ci.sparc.SPARC.d40; -import static jdk.vm.ci.sparc.SPARC.d42; -import static jdk.vm.ci.sparc.SPARC.d44; -import static jdk.vm.ci.sparc.SPARC.d46; -import static jdk.vm.ci.sparc.SPARC.d48; -import static jdk.vm.ci.sparc.SPARC.d50; -import static jdk.vm.ci.sparc.SPARC.d52; -import static jdk.vm.ci.sparc.SPARC.d54; -import static jdk.vm.ci.sparc.SPARC.d56; -import static jdk.vm.ci.sparc.SPARC.d58; -import static jdk.vm.ci.sparc.SPARC.d60; -import static jdk.vm.ci.sparc.SPARC.d62; -import static jdk.vm.ci.sparc.SPARC.f10; -import static jdk.vm.ci.sparc.SPARC.f11; -import static jdk.vm.ci.sparc.SPARC.f12; -import static jdk.vm.ci.sparc.SPARC.f13; -import static jdk.vm.ci.sparc.SPARC.f14; -import static jdk.vm.ci.sparc.SPARC.f15; -import static jdk.vm.ci.sparc.SPARC.f16; -import static jdk.vm.ci.sparc.SPARC.f17; -import static jdk.vm.ci.sparc.SPARC.f18; -import static jdk.vm.ci.sparc.SPARC.f19; -import static jdk.vm.ci.sparc.SPARC.f20; -import static jdk.vm.ci.sparc.SPARC.f21; -import static jdk.vm.ci.sparc.SPARC.f22; -import static jdk.vm.ci.sparc.SPARC.f23; -import static jdk.vm.ci.sparc.SPARC.f24; -import static jdk.vm.ci.sparc.SPARC.f25; -import static jdk.vm.ci.sparc.SPARC.f26; -import static jdk.vm.ci.sparc.SPARC.f27; -import static jdk.vm.ci.sparc.SPARC.f28; -import static jdk.vm.ci.sparc.SPARC.f29; -import static jdk.vm.ci.sparc.SPARC.f30; -import static jdk.vm.ci.sparc.SPARC.f31; -import static jdk.vm.ci.sparc.SPARC.f8; -import static jdk.vm.ci.sparc.SPARC.f9; -import static jdk.vm.ci.sparc.SPARC.g1; -import static jdk.vm.ci.sparc.SPARC.g4; -import static jdk.vm.ci.sparc.SPARC.g5; -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.i1; -import static jdk.vm.ci.sparc.SPARC.i2; -import static jdk.vm.ci.sparc.SPARC.i3; -import static jdk.vm.ci.sparc.SPARC.i4; -import static jdk.vm.ci.sparc.SPARC.i5; -import static jdk.vm.ci.sparc.SPARC.l0; -import static jdk.vm.ci.sparc.SPARC.l1; -import static jdk.vm.ci.sparc.SPARC.l2; -import static jdk.vm.ci.sparc.SPARC.l3; -import static jdk.vm.ci.sparc.SPARC.l4; -import static jdk.vm.ci.sparc.SPARC.l5; -import static jdk.vm.ci.sparc.SPARC.l6; -import static jdk.vm.ci.sparc.SPARC.l7; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o1; -import static jdk.vm.ci.sparc.SPARC.o2; -import static jdk.vm.ci.sparc.SPARC.o3; -import static jdk.vm.ci.sparc.SPARC.o4; -import static jdk.vm.ci.sparc.SPARC.o5; - -import java.util.ArrayList; -import java.util.BitSet; - -import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterArray; -import jdk.vm.ci.code.RegisterConfig; - -public class SPARCHotSpotRegisterAllocationConfig extends RegisterAllocationConfig { - - // @formatter:off - static final Register[] registerAllocationOrder = { - l0, l1, l2, l3, l4, l5, l6, l7, - i0, i1, i2, i3, i4, i5, /*i6,*/ /*i7,*/ - o0, o1, o2, o3, o4, o5, /*o6, o7,*/ - g1, g4, g5, - // f0, f1, f2, f3, f4, f5, f6, f7 - f8, f9, f10, f11, f12, f13, f14, f15, - f16, f17, f18, f19, f20, f21, f22, f23, - f24, f25, f26, f27, f28, f29, f30, f31, - d32, d34, d36, d38, d40, d42, d44, d46, - d48, d50, d52, d54, d56, d58, d60, d62 - }; - // @formatter:on - - public SPARCHotSpotRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) { - super(registerConfig, allocationRestrictedTo); - } - - @Override - protected RegisterArray initAllocatable(RegisterArray registers) { - BitSet regMap = new BitSet(registerConfig.getAllocatableRegisters().size()); - for (Register reg : registers) { - regMap.set(reg.number); - } - - ArrayList allocatableRegisters = new ArrayList<>(registers.size()); - for (Register reg : registerAllocationOrder) { - if (regMap.get(reg.number)) { - allocatableRegisters.add(reg); - } - } - - return super.initAllocatable(new RegisterArray(allocatableRegisters)); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotReturnOp.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARC.sp; -import static org.graalvm.compiler.hotspot.HotSpotHostBackend.ENABLE_STACK_RESERVED_ZONE; -import static org.graalvm.compiler.hotspot.HotSpotHostBackend.THROW_DELAYED_STACKOVERFLOW_ERROR; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow.ReturnOp; - -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterValue; -import jdk.vm.ci.meta.Value; - -/** - * Returns from a function. - */ -@Opcode("RETURN") -final class SPARCHotSpotReturnOp extends SPARCHotSpotEpilogueOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotReturnOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(2); - - @Use({REG, ILLEGAL}) protected Value value; - @Use({REG, ILLEGAL}) protected Value safepointPollAddress; - private final boolean requiresReservedStackAccessCheck; - private final boolean isStub; - private final GraalHotSpotVMConfig config; - private final Register thread; - - SPARCHotSpotReturnOp(Value value, boolean isStub, GraalHotSpotVMConfig config, Register thread, Value safepointPoll, boolean requiresReservedStackAccessCheck) { - super(TYPE, SIZE); - this.value = value; - this.isStub = isStub; - this.config = config; - this.thread = thread; - this.safepointPollAddress = safepointPoll; - this.requiresReservedStackAccessCheck = requiresReservedStackAccessCheck; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - if (!isStub) { - if (requiresReservedStackAccessCheck) { - try (ScratchRegister sc = masm.getScratchRegister()) { - HotSpotForeignCallsProvider foreignCalls = (HotSpotForeignCallsProvider) crb.foreignCalls; - Label noReserved = new Label(); - Register scratch = sc.getRegister(); - masm.ldx(new SPARCAddress(thread, config.javaThreadReservedStackActivationOffset), scratch); - masm.compareBranch(sp, scratch, SPARCAssembler.ConditionFlag.LessUnsigned, SPARCAssembler.CC.Xcc, noReserved, SPARCAssembler.BranchPredict.PREDICT_TAKEN, null); - ForeignCallLinkage enableStackReservedZone = foreignCalls.lookupForeignCall(ENABLE_STACK_RESERVED_ZONE); - CallingConvention cc = enableStackReservedZone.getOutgoingCallingConvention(); - assert cc.getArgumentCount() == 1; - Register arg0 = ((RegisterValue) cc.getArgument(0)).getRegister(); - masm.mov(thread, arg0); - SPARCCall.directCall(crb, masm, enableStackReservedZone, scratch, null); - masm.restoreWindow(); - SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(THROW_DELAYED_STACKOVERFLOW_ERROR)); - masm.bind(noReserved); - } - } - // Every non-stub compile method must have a poll before the return. - SPARCHotSpotSafepointOp.emitCode(crb, masm, config, true, null, thread, safepointPollAddress); - } - ReturnOp.emitCodeHelper(crb, masm); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotSafepointOp.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2011, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.g0; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import org.graalvm.compiler.lir.sparc.SPARCLIRInstruction; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.ValueUtil; -import jdk.vm.ci.code.site.InfopointReason; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Value; - -/** - * Emits a safepoint poll. - */ -@Opcode("SAFEPOINT") -public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotSafepointOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(9); - - @State protected LIRFrameState state; - @Use({OperandFlag.REG, OperandFlag.ILLEGAL}) AllocatableValue safepointPollAddress; - private final GraalHotSpotVMConfig config; - private final Register thread; - - public SPARCHotSpotSafepointOp(LIRFrameState state, GraalHotSpotVMConfig config, Register thread, LIRGeneratorTool tool) { - super(TYPE, SIZE); - this.state = state; - this.config = config; - this.thread = thread; - SPARCHotSpotLIRGenerator lirGen = (SPARCHotSpotLIRGenerator) tool; - safepointPollAddress = lirGen.getSafepointAddressValue(); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - emitCode(crb, masm, config, false, state, thread, safepointPollAddress); - } - - public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread, - Value safepointPollAddress) { - if (config.threadLocalHandshakes) { - emitThreadLocalPoll(crb, masm, config, atReturn, state, thread); - } else { - emitGlobalPoll(crb, masm, config, atReturn, state, asRegister(safepointPollAddress)); - } - } - - /** - * Emit a global safepoint poll. - */ - private static void emitGlobalPoll(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register safepointPollAddress) { - crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); - if (state != null) { - final int pos = masm.position(); - crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); - } - masm.ldx(new SPARCAddress(safepointPollAddress, 0), g0); - } - - /** - * Emit a thread-local safepoint poll. - */ - private static void emitThreadLocalPoll(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread) { - assert !atReturn || state == null : "state is unneeded at return"; - - assert config.threadPollingPageOffset >= 0; - - try (ScratchRegister scratchReg = masm.getScratchRegister()) { - Register scratch = scratchReg.getRegister(); - - masm.ldx(new SPARCAddress(thread, config.threadPollingPageOffset), scratch); - - crb.recordMark(atReturn ? config.MARKID_POLL_RETURN_FAR : config.MARKID_POLL_FAR); - if (state != null) { - final int pos = masm.position(); - crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT); - } - masm.ldx(new SPARCAddress(scratch, 0), g0); - } - } - - static AllocatableValue getSafepointAddressValue(SPARCHotSpotLIRGenerator gen) { - if (gen.config.threadLocalHandshakes) { - return Value.ILLEGAL; - } else { - return gen.newVariable(LIRKind.value(gen.target().arch.getWordKind())); - } - } - - static void emitPrologue(SPARCHotSpotNodeLIRBuilder lir, SPARCHotSpotLIRGenerator gen) { - if (!gen.config.threadLocalHandshakes) { - AllocatableValue var = gen.getSafepointAddressValue(); - lir.append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, gen.config)); - gen.append(((HotSpotDebugInfoBuilder) lir.getDebugInfoBuilder()).lockStack()); - } - } - - public static class SPARCLoadSafepointPollAddress extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCLoadSafepointPollAddress.class); - public static final SizeEstimate SIZE = SizeEstimate.create(2); - - @Def({OperandFlag.REG}) protected AllocatableValue result; - private final GraalHotSpotVMConfig config; - - public SPARCLoadSafepointPollAddress(AllocatableValue result, GraalHotSpotVMConfig config) { - super(TYPE, SIZE); - this.result = result; - this.config = config; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - masm.setx(config.safepointPollingAddress, ValueUtil.asRegister(result), false); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.g0; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.INSTRUCTION_SIZE; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; -import static org.graalvm.compiler.lir.sparc.SPARCMove.loadFromConstantTable; - -import org.graalvm.compiler.asm.Assembler.LabelHint; -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.calc.Condition; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.LabelRef; -import org.graalvm.compiler.lir.SwitchStrategy; -import org.graalvm.compiler.lir.Variable; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCControlFlow; -import org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARC.CPUFeature; - -final class SPARCHotSpotStrategySwitchOp extends SPARCControlFlow.StrategySwitchOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotStrategySwitchOp.class); - - SPARCHotSpotStrategySwitchOp(Value constantTableBase, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, AllocatableValue key, Variable scratch) { - super(TYPE, constantTableBase, strategy, keyTargets, defaultTarget, key, scratch); - } - - public class HotSpotSwitchClosure extends SwitchClosure { - protected HotSpotSwitchClosure(Register keyRegister, Register constantBaseRegister, CompilationResultBuilder crb, SPARCMacroAssembler masm) { - super(keyRegister, constantBaseRegister, crb, masm); - } - - @Override - protected void conditionalJump(int index, Condition condition, Label target) { - if (keyConstants[index] instanceof HotSpotMetaspaceConstant) { - HotSpotMetaspaceConstant constant = (HotSpotMetaspaceConstant) keyConstants[index]; - CC conditionCode = constant.isCompressed() ? CC.Icc : CC.Xcc; - ConditionFlag conditionFlag = SPARCControlFlow.fromCondition(true, condition, false); - LabelHint hint = requestHint(masm, target); - - // Load constant takes one instruction - int cbCondPosition = masm.position() + INSTRUCTION_SIZE; - boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && SPARCControlFlow.isShortBranch(masm, cbCondPosition, hint, target); - - Register scratchRegister = asRegister(scratch); - loadFromConstantTable(crb, masm, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY); - - if (canUseShortBranch) { - CBCOND.emit(masm, conditionFlag, conditionCode == CC.Xcc, keyRegister, scratchRegister, target); - } else { - masm.cmp(keyRegister, scratchRegister); - BPCC.emit(masm, conditionCode, conditionFlag, ANNUL, PREDICT_TAKEN, target); - masm.nop(); // delay slot - } - } else { - super.conditionalJump(index, condition, target); - } - } - } - - @Override - protected int estimateEmbeddedSize(Constant c) { - if (c instanceof HotSpotMetaspaceConstant) { - return ((HotSpotMetaspaceConstant) c).isCompressed() ? 4 : 8; - } else { - return super.estimateEmbeddedSize(c); - } - } - - @Override - public void emitCode(final CompilationResultBuilder crb, final SPARCMacroAssembler masm) { - final Register keyRegister = asRegister(key); - final Register constantBaseRegister = AllocatableValue.ILLEGAL.equals(constantTableBase) ? g0 : asRegister(constantTableBase); - strategy.run(new HotSpotSwitchClosure(keyRegister, constantBaseRegister, crb, masm)); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotUnwindOp.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.g5; -import static jdk.vm.ci.sparc.SPARC.i0; -import static jdk.vm.ci.sparc.SPARC.o0; -import static jdk.vm.ci.sparc.SPARC.o7; - -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall; - -import jdk.vm.ci.code.CallingConvention; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterValue; - -/** - * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}. - */ -@Opcode("UNWIND") -final class SPARCHotSpotUnwindOp extends SPARCHotSpotEpilogueOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotSpotUnwindOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(32); - - @Use({REG}) protected RegisterValue exception; - - SPARCHotSpotUnwindOp(RegisterValue exception) { - super(TYPE, SIZE); - this.exception = exception; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // This Frame is left but the called unwind (which is sibling) method needs the exception as - // input in i0 - masm.mov(o0, i0); - leaveFrame(crb); - - ForeignCallLinkage linkage = crb.foreignCalls.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER); - CallingConvention cc = linkage.getOutgoingCallingConvention(); - assert cc.getArgumentCount() == 2; - assert exception.equals(cc.getArgument(0)); - - // Get return address (is in o7 after leave). - Register returnAddress = asRegister(cc.getArgument(1)); - masm.add(o7, SPARCAssembler.PC_RETURN_OFFSET, returnAddress); - Register scratch = g5; - SPARCCall.indirectJmp(crb, masm, scratch, linkage); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp; -import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; - -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Value; - -/** - * A direct call that complies with the conventions for such calls in HotSpot. It doesn't use an - * inline cache so it's just a patchable call site. - */ -@Opcode("CALL_DIRECT") -final class SPARCHotspotDirectStaticCallOp extends DirectCallOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotspotDirectStaticCallOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(8); - - private final InvokeKind invokeKind; - private final GraalHotSpotVMConfig config; - - SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { - super(TYPE, SIZE, target, result, parameters, temps, state); - assert invokeKind.isDirect(); - this.invokeKind = invokeKind; - this.config = config; - } - - @Override - public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static jdk.vm.ci.sparc.SPARC.g5; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp; -import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Value; - -/** - * A direct call that complies with the conventions for such calls in HotSpot. In particular, for - * calls using an inline cache, a MOVE instruction is emitted just prior to the aligned direct call. - */ -@Opcode("CALL_DIRECT") -final class SPARCHotspotDirectVirtualCallOp extends DirectCallOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCHotspotDirectVirtualCallOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(8); - - private final InvokeKind invokeKind; - private final GraalHotSpotVMConfig config; - - SPARCHotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) { - super(TYPE, SIZE, target, result, parameters, temps, state); - this.invokeKind = invokeKind; - this.config = config; - assert invokeKind.isIndirect(); - } - - @Override - public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // The mark for an invocation that uses an inline cache must be placed at the - // instruction that loads the Klass from the inline cache. - crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE); - Register scratchRegister = g5; - masm.setx(config.nonOopBits, scratchRegister, true); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCIndirectCallOp.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.g5; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.sparc.SPARCCall; -import org.graalvm.compiler.lir.sparc.SPARCCall.IndirectCallOp; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Value; - -/** - * A register indirect call that complies with the extra conventions for such calls in HotSpot. In - * particular, the metaspace Method of the callee must be in g5 for the case where a vtable entry's - * _from_compiled_entry is the address of an C2I adapter. Such adapters expect the target method to - * be in g5. - */ -@Opcode("CALL_INDIRECT") -final class SPARCIndirectCallOp extends IndirectCallOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCIndirectCallOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(2); - - /** - * Vtable stubs expect the metaspace Method in g5. - */ - public static final Register METHOD = g5; - - @Use({REG}) protected Value metaspaceMethod; - - private final GraalHotSpotVMConfig config; - - SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state, - GraalHotSpotVMConfig config) { - super(TYPE, SIZE, targetMethod, result, parameters, temps, targetAddress, state); - this.metaspaceMethod = metaspaceMethod; - this.config = config; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - crb.recordMark(config.MARKID_INLINE_INVOKE); - Register callReg = asRegister(targetAddress); - assert !callReg.equals(METHOD); - SPARCCall.indirectCall(crb, masm, callReg, callTarget, state); - } - - @Override - public void verify() { - super.verify(); - assert asRegister(metaspaceMethod).equals(METHOD); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/AheadOfTimeCompilationTest.java @@ -67,7 +67,7 @@ @Before public void setUp() { - // Ignore on SPARC + // Ignore on AArch64 Assume.assumeFalse("skipping on AArch64", getTarget().arch instanceof AArch64); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java @@ -61,7 +61,6 @@ import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.sparc.SPARC; /** * Checks the intrinsics implemented by Graal against the set of intrinsics declared by HotSpot. The @@ -373,10 +372,6 @@ add(ignore, "java/lang/Math.fma(DDD)D", "java/lang/Math.fma(FFF)F"); - } else if (arch instanceof SPARC) { - add(toBeInvestigated, - "java/lang/Math.fma(DDD)D", - "java/lang/Math.fma(FFF)F"); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -414,11 +414,6 @@ return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_last_Java_fp", Integer.class, "intptr_t*"); } - public int threadJavaFrameAnchorFlagsOffset() { - assert osArch.equals("sparc"); - return javaThreadAnchorOffset + getFieldOffset("JavaFrameAnchor::_flags", Integer.class, "int"); - } - public final int runtimeCallStackSize = getConstant("frame::arg_reg_save_area_bytes", Integer.class, intRequiredOnAMD64); public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, intRequiredOnAMD64); public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, intRequiredOnAMD64); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigBase.java @@ -103,9 +103,6 @@ case "Linux": osName = "linux"; break; - case "SunOS": - osName = "solaris"; - break; case "Mac OS X": osName = "bsd"; break; @@ -126,9 +123,6 @@ case "x86_64": arch = "amd64"; break; - case "sparcv9": - arch = "sparc"; - break; } return arch; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -550,7 +550,7 @@ assert config.cipherBlockChainingEncryptAESCryptStub != 0L; assert config.cipherBlockChainingDecryptAESCryptStub != 0L; String arch = config.osArch; - String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : ""; + String decryptSuffix = ""; Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", replacements); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt/SPARCBranchBailoutTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2016, 2018, 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 org.graalvm.compiler.lir.jtt; - -import org.graalvm.compiler.api.directives.GraalDirectives; -import org.graalvm.compiler.asm.BranchTargetOutOfBoundsException; -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.debug.DebugContext.Scope; -import org.graalvm.compiler.lir.LIRInstruction; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; -import org.junit.Assume; -import org.junit.Test; - -import jdk.vm.ci.code.BailoutException; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARC; - -/** - * Tests the {@link BailoutException} thrown, when trying to compile huge methods, which have branch - * displacements which does not fit into 19 bit signed. - */ -public class SPARCBranchBailoutTest extends LIRTest { - private static class BranchSpec extends LIRTestSpecification { - private final int n; - - BranchSpec(int n) { - super(); - this.n = n; - } - - @Override - public void generate(LIRGeneratorTool gen, Value a) { - gen.append(new LargeOp(n)); - setResult(a); - } - } - - private static final BranchSpec spec = new BranchSpec(1 << 20); - - @LIRIntrinsic - public static int branch(@SuppressWarnings("unused") BranchSpec s, int a) { - return a; - } - - public static int testBranch(int length) { - int res = 1; - if (length > 0) { - res = branch(spec, 1); - } else { - res = branch(spec, 2); - } - return GraalDirectives.opaque(res); - } - - @SuppressWarnings("try") - @Test(expected = BranchTargetOutOfBoundsException.class) - public void testBailoutOnBranchOverflow() throws Throwable { - Assume.assumeTrue(getBackend().getTarget().arch instanceof SPARC); - ResolvedJavaMethod m = getResolvedJavaMethod("testBranch"); - DebugContext debug = getDebugContext(); - try (Scope s = debug.disable()) { - StructuredGraph graph = parseEager(m, AllowAssumptions.YES, debug); - compile(m, graph); - } - } - - public static class LargeOp extends LIRInstruction { - private static final LIRInstructionClass TYPE = LIRInstructionClass.create(LargeOp.class); - private final int n; - - public LargeOp(int n) { - super(TYPE); - this.n = n; - } - - @Override - public void emitCode(CompilationResultBuilder crb) { - for (int i = 0; i < n; i++) { - crb.asm.emitInt(0); - } - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCAddressValue.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.lir.sparc; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.lir.CompositeValue; - -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.meta.ValueKind; - -public abstract class SPARCAddressValue extends CompositeValue { - - public SPARCAddressValue(ValueKind kind) { - super(kind); - } - - public abstract SPARCAddress toAddress(); - - public abstract boolean isValidImplicitNullCheckFor(Value value, int implicitNullCheckLimit); -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArithmetic.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.lir.sparc; - -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_V_SHIFT; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CCR_XCC_SHIFT; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Ordered; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmpd; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Opfs.Fcmps; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isRegister; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.DOUBLE; -import static jdk.vm.ci.sparc.SPARCKind.SINGLE; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARC; - -public class SPARCArithmetic { - public static final class FloatConvertOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(FloatConvertOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(5); - - @Opcode private final FloatConvert opcode; - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG}) protected Value x; - - public enum FloatConvert { - F2I, - D2I, - F2L, - D2L - } - - public FloatConvertOp(FloatConvert opcode, Value x, AllocatableValue result) { - super(TYPE, SIZE); - this.opcode = opcode; - this.x = x; - this.result = result; - } - - @Override - protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Label notOrdered = new Label(); - switch (opcode) { - case F2L: - masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); - FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); - masm.fstox(asRegister(x, SINGLE), asRegister(result, DOUBLE)); - masm.fxtod(asRegister(result), asRegister(result)); - masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); - masm.bind(notOrdered); - break; - case F2I: - masm.fcmp(Fcc0, Fcmps, asRegister(x, SINGLE), asRegister(x, SINGLE)); - FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); - masm.fstoi(asRegister(x, SINGLE), asRegister(result, SINGLE)); - masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); - masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); - masm.bind(notOrdered); - break; - case D2L: - masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); - FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); - masm.fdtox(asRegister(x, DOUBLE), asRegister(result, DOUBLE)); - masm.fxtod(asRegister(result, DOUBLE), asRegister(result, DOUBLE)); - masm.fsubd(asRegister(result, DOUBLE), asRegister(result, DOUBLE), asRegister(result, DOUBLE)); - masm.bind(notOrdered); - break; - case D2I: - masm.fcmp(Fcc0, Fcmpd, asRegister(x, DOUBLE), asRegister(x, DOUBLE)); - FBPCC.emit(masm, Fcc0, F_Ordered, ANNUL, PREDICT_TAKEN, notOrdered); - masm.fdtoi(asRegister(x, DOUBLE), asRegister(result, SINGLE)); - masm.fitos(asRegister(result, SINGLE), asRegister(result, SINGLE)); - masm.fsubs(asRegister(result, SINGLE), asRegister(result, SINGLE), asRegister(result, SINGLE)); - masm.bind(notOrdered); - break; - default: - throw GraalError.shouldNotReachHere("missing: " + opcode); - } - } - } - - /** - * Special LIR instruction as it requires a bunch of scratch registers. - */ - public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(RemOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(4); - - @Opcode private final Rem opcode; - @Def({REG}) protected AllocatableValue result; - @Alive({REG, CONST}) protected Value x; - @Alive({REG, CONST}) protected Value y; - @Temp({REG}) protected AllocatableValue scratch1; - @Temp({REG}) protected AllocatableValue scratch2; - @State protected LIRFrameState state; - - public enum Rem { - IUREM, - LUREM - } - - public RemOp(Rem opcode, AllocatableValue result, Value x, Value y, AllocatableValue scratch1, AllocatableValue scratch2, LIRFrameState state) { - super(TYPE, SIZE); - this.opcode = opcode; - this.result = result; - this.x = x; - this.y = y; - this.scratch1 = scratch1; - this.scratch2 = scratch2; - this.state = state; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - if (!isJavaConstant(x) && isJavaConstant(y)) { - assert isSimm13(crb.asIntConst(y)); - assert !x.equals(scratch1); - assert !x.equals(scratch2); - assert !y.equals(scratch1); - switch (opcode) { - case LUREM: - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - masm.udivx(asRegister(x, XWORD), crb.asIntConst(y), asRegister(scratch1, XWORD)); - masm.mulx(asRegister(scratch1, XWORD), crb.asIntConst(y), asRegister(scratch2, XWORD)); - getDelayedControlTransfer().emitControlTransfer(crb, masm); - masm.sub(asRegister(x, XWORD), asRegister(scratch2, XWORD), asRegister(result, XWORD)); - break; - case IUREM: - GraalError.unimplemented(); - break; - default: - throw GraalError.shouldNotReachHere(); - } - } else if (isRegister(x) && isRegister(y)) { - Value xLeft = x; - switch (opcode) { - case LUREM: - if (isJavaConstant(x)) { - masm.setx(crb.asLongConst(x), asRegister(scratch2, XWORD), false); - xLeft = scratch2; - } - assert !asRegister(xLeft, XWORD).equals(asRegister(scratch1, XWORD)); - assert !asRegister(y, XWORD).equals(asRegister(scratch1, XWORD)); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - masm.udivx(asRegister(xLeft, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); - masm.mulx(asRegister(scratch1, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); - getDelayedControlTransfer().emitControlTransfer(crb, masm); - masm.sub(asRegister(xLeft, XWORD), asRegister(scratch1, XWORD), asRegister(result, XWORD)); - break; - case IUREM: - assert !asRegister(result, WORD).equals(asRegister(scratch1, WORD)); - assert !asRegister(result, WORD).equals(asRegister(scratch2, WORD)); - masm.srl(asRegister(x, WORD), 0, asRegister(scratch1, WORD)); - masm.srl(asRegister(y, WORD), 0, asRegister(result, WORD)); - if (state != null) { - crb.recordImplicitException(masm.position(), state); - } - masm.udivx(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(scratch2, WORD)); - masm.mulx(asRegister(scratch2, WORD), asRegister(result, WORD), asRegister(result, WORD)); - getDelayedControlTransfer().emitControlTransfer(crb, masm); - masm.sub(asRegister(scratch1, WORD), asRegister(result, WORD), asRegister(result, WORD)); - break; - default: - throw GraalError.shouldNotReachHere(); - } - } else { - throw GraalError.shouldNotReachHere(); - } - } - } - - public static final class SPARCIMulccOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCIMulccOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(10); - @Def({REG}) protected AllocatableValue result; - @Alive({REG}) protected AllocatableValue x; - @Alive({REG}) protected AllocatableValue y; - - public SPARCIMulccOp(AllocatableValue result, AllocatableValue x, AllocatableValue y) { - super(TYPE, SIZE); - this.result = result; - this.x = x; - this.y = y; - } - - @Override - protected void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (ScratchRegister tmpScratch = masm.getScratchRegister()) { - Register tmp = tmpScratch.getRegister(); - Register resultRegister = asRegister(result, WORD); - Register xRegister = asRegister(x, WORD); - Register yRegister = asRegister(y, WORD); - masm.sra(xRegister, 0, xRegister); - masm.sra(yRegister, 0, yRegister); - masm.mulx(xRegister, yRegister, resultRegister); - Label noOverflow = new Label(); - masm.sra(resultRegister, 0, tmp); - masm.compareBranch(tmp, resultRegister, Equal, Xcc, noOverflow, PREDICT_TAKEN, null); - masm.wrccr(SPARC.g0, 1 << (SPARCAssembler.CCR_ICC_SHIFT + SPARCAssembler.CCR_V_SHIFT)); - masm.bind(noOverflow); - } - } - } - - /** - * Calculates the product and condition code for long multiplication of long values. - */ - public static final class SPARCLMulccOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCLMulccOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(13); - - @Def({REG}) protected AllocatableValue result; - @Alive({REG}) protected AllocatableValue x; - @Alive({REG}) protected AllocatableValue y; - @Temp({REG}) protected AllocatableValue scratch1; - @Temp({REG}) protected AllocatableValue scratch2; - - public SPARCLMulccOp(AllocatableValue result, AllocatableValue x, AllocatableValue y, LIRGeneratorTool gen) { - super(TYPE, SIZE); - this.result = result; - this.x = x; - this.y = y; - this.scratch1 = gen.newVariable(LIRKind.combine(x, y)); - this.scratch2 = gen.newVariable(LIRKind.combine(x, y)); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Label noOverflow = new Label(); - masm.mulx(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); - - // Calculate the upper 64 bit signed := (umulxhi product - (x{63}&y + y{63}&x)) - masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(scratch1, XWORD)); - masm.srax(asRegister(x, XWORD), 63, asRegister(scratch2, XWORD)); - masm.and(asRegister(scratch2, XWORD), asRegister(y, XWORD), asRegister(scratch2, XWORD)); - masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); - - masm.srax(asRegister(y, XWORD), 63, asRegister(scratch2, XWORD)); - masm.and(asRegister(scratch2, XWORD), asRegister(x, XWORD), asRegister(scratch2, XWORD)); - masm.sub(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD), asRegister(scratch1, XWORD)); - - // Now construct the lower half and compare - masm.srax(asRegister(result, XWORD), 63, asRegister(scratch2, XWORD)); - masm.cmp(asRegister(scratch1, XWORD), asRegister(scratch2, XWORD)); - BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_TAKEN, noOverflow); - masm.nop(); - masm.wrccr(g0, 1 << (CCR_XCC_SHIFT + CCR_V_SHIFT)); - masm.bind(noOverflow); - } - } - - public static final class MulHighOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(MulHighOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(4); - - @Opcode private final MulHigh opcode; - @Def({REG}) public AllocatableValue result; - @Alive({REG}) public AllocatableValue x; - @Alive({REG}) public AllocatableValue y; - @Temp({REG}) public AllocatableValue scratch; - - public enum MulHigh { - IMUL, - LMUL - } - - public MulHighOp(MulHigh opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) { - super(TYPE, SIZE); - this.opcode = opcode; - this.x = x; - this.y = y; - this.scratch = scratch; - this.result = result; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert isRegister(x) && isRegister(y) && isRegister(result) && isRegister(scratch); - switch (opcode) { - case IMUL: - masm.sra(asRegister(x), 0, asRegister(x)); - masm.sra(asRegister(y), 0, asRegister(y)); - masm.mulx(asRegister(x, WORD), asRegister(y, WORD), asRegister(result, WORD)); - masm.srax(asRegister(result, WORD), 32, asRegister(result, WORD)); - break; - case LMUL: - assert !asRegister(scratch, XWORD).equals(asRegister(result, XWORD)); - masm.umulxhi(asRegister(x, XWORD), asRegister(y, XWORD), asRegister(result, XWORD)); - - masm.srlx(asRegister(x, XWORD), 63, asRegister(scratch, XWORD)); - masm.mulx(asRegister(scratch, XWORD), asRegister(y, XWORD), asRegister(scratch, XWORD)); - masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); - - masm.srlx(asRegister(y, XWORD), 63, asRegister(scratch, XWORD)); - masm.mulx(asRegister(scratch, XWORD), asRegister(x, XWORD), asRegister(scratch, XWORD)); - masm.sub(asRegister(result, XWORD), asRegister(scratch, XWORD), asRegister(result, XWORD)); - break; - default: - throw GraalError.shouldNotReachHere(); - } - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.lir.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Less; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.sparc.SPARCKind; - -/** - * Emits code which compares two arrays of the same length. - */ -@Opcode("ARRAY_EQUALS") -public final class SPARCArrayEqualsOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCArrayEqualsOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(32); - - private final JavaKind kind; - private final int arrayBaseOffset; - private final int arrayIndexScale; - - @Def({REG}) protected AllocatableValue resultValue; - @Alive({REG}) protected AllocatableValue array1Value; - @Alive({REG}) protected AllocatableValue array2Value; - @Alive({REG}) protected AllocatableValue lengthValue; - @Temp({REG}) protected AllocatableValue temp1; - @Temp({REG}) protected AllocatableValue temp2; - @Temp({REG}) protected AllocatableValue temp3; - @Temp({REG}) protected AllocatableValue temp4; - @Temp({REG}) protected AllocatableValue temp5; - - public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, AllocatableValue result, AllocatableValue array1, AllocatableValue array2, AllocatableValue length, boolean directPointers) { - super(TYPE, SIZE); - - assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; - this.kind = kind; - - this.arrayBaseOffset = directPointers ? 0 : tool.getProviders().getMetaAccess().getArrayBaseOffset(kind); - this.arrayIndexScale = tool.getProviders().getMetaAccess().getArrayIndexScale(kind); - - this.resultValue = result; - this.array1Value = array1; - this.array2Value = array2; - this.lengthValue = length; - - // Allocate some temporaries. - this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); - this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind())); - this.temp3 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); - this.temp4 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); - this.temp5 = tool.newVariable(LIRKind.value(tool.target().arch.getWordKind())); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register result = asRegister(resultValue); - Register array1 = asRegister(temp1); - Register array2 = asRegister(temp2); - Register length = asRegister(temp3); - - Label trueLabel = new Label(); - Label falseLabel = new Label(); - Label done = new Label(); - - // Load array base addresses. - masm.add(asRegister(array1Value), arrayBaseOffset, array1); - masm.add(asRegister(array2Value), arrayBaseOffset, array2); - - // Get array length in bytes. - masm.mulx(asRegister(lengthValue, WORD), arrayIndexScale, length); - masm.mov(length, result); // copy - - emit8ByteCompare(masm, result, array1, array2, length, trueLabel, falseLabel); - emitTailCompares(masm, result, array1, array2, trueLabel, falseLabel); - - // Return true - masm.bind(trueLabel); - masm.mov(1, result); - masm.jmp(done); - - // Return false - masm.bind(falseLabel); - masm.mov(g0, result); - - // That's it - masm.bind(done); - } - - /** - * Vector size used in {@link #emit8ByteCompare}. - */ - private static final int VECTOR_SIZE = 8; - - /** - * Emits code that uses 8-byte vector compares. - */ - private void emit8ByteCompare(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { - assert lengthValue.getPlatformKind().equals(SPARCKind.WORD); - Label loop = new Label(); - Label compareTail = new Label(); - Label compareTailCorrectVectorEnd = new Label(); - - Register tempReg1 = asRegister(temp4); - Register tempReg2 = asRegister(temp5); - - masm.sra(length, 0, length); - masm.and(result, VECTOR_SIZE - 1, result); // tail count (in bytes) - masm.andcc(length, ~(VECTOR_SIZE - 1), length); // vector count (in bytes) - BPCC.emit(masm, Xcc, Equal, NOT_ANNUL, PREDICT_NOT_TAKEN, compareTail); - - masm.sub(length, VECTOR_SIZE, length); // Delay slot - masm.add(array1, length, array1); - masm.add(array2, length, array2); - masm.sub(g0, length, length); - - // Compare the last element first - masm.ldx(new SPARCAddress(array1, 0), tempReg1); - masm.ldx(new SPARCAddress(array2, 0), tempReg2); - masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_NOT_TAKEN, null); - masm.compareBranch(length, 0, Equal, Xcc, compareTailCorrectVectorEnd, PREDICT_NOT_TAKEN, null); - - // Load the first value from array 1 (Later done in back branch delay-slot) - masm.ldx(new SPARCAddress(array1, length), tempReg1); - masm.bind(loop); - masm.ldx(new SPARCAddress(array2, length), tempReg2); - masm.cmp(tempReg1, tempReg2); - - BPCC.emit(masm, Xcc, NotEqual, NOT_ANNUL, PREDICT_NOT_TAKEN, falseLabel); - // Delay slot, not annul, add for next iteration - masm.addcc(length, VECTOR_SIZE, length); - // Annul, to prevent access past the array - BPCC.emit(masm, Xcc, NotEqual, ANNUL, PREDICT_TAKEN, loop); - masm.ldx(new SPARCAddress(array1, length), tempReg1); // Load in delay slot - - // Tail count zero, therefore we can go to the end - masm.compareBranch(result, 0, Equal, Xcc, trueLabel, PREDICT_TAKEN, null); - - masm.bind(compareTailCorrectVectorEnd); - // Correct the array pointers - masm.add(array1, VECTOR_SIZE, array1); - masm.add(array2, VECTOR_SIZE, array2); - - masm.bind(compareTail); - } - - /** - * Emits code to compare the remaining 1 to 4 bytes. - */ - private void emitTailCompares(SPARCMacroAssembler masm, Register result, Register array1, Register array2, Label trueLabel, Label falseLabel) { - Label compare2Bytes = new Label(); - Label compare1Byte = new Label(); - - Register tempReg1 = asRegister(temp3); - Register tempReg2 = asRegister(temp4); - - if (kind.getByteCount() <= 4) { - // Compare trailing 4 bytes, if any. - masm.compareBranch(result, 4, Less, Xcc, compare2Bytes, PREDICT_NOT_TAKEN, null); - - masm.lduw(new SPARCAddress(array1, 0), tempReg1); - masm.lduw(new SPARCAddress(array2, 0), tempReg2); - masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_NOT_TAKEN, null); - - if (kind.getByteCount() <= 2) { - // Move array pointers forward. - masm.add(array1, 4, array1); - masm.add(array2, 4, array2); - masm.sub(result, 4, result); - - // Compare trailing 2 bytes, if any. - masm.bind(compare2Bytes); - - masm.compareBranch(result, 2, Less, Xcc, compare1Byte, PREDICT_TAKEN, null); - - masm.lduh(new SPARCAddress(array1, 0), tempReg1); - masm.lduh(new SPARCAddress(array2, 0), tempReg2); - - masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_TAKEN, null); - - // The one-byte tail compare is only required for boolean and byte arrays. - if (kind.getByteCount() <= 1) { - // Move array pointers forward before we compare the last trailing byte. - masm.add(array1, 2, array1); - masm.add(array2, 2, array2); - masm.sub(result, 2, result); - - // Compare trailing byte, if any. - masm.bind(compare1Byte); - masm.compareBranch(result, 1, NotEqual, Xcc, trueLabel, PREDICT_TAKEN, null); - - masm.ldub(new SPARCAddress(array1, 0), tempReg1); - masm.ldub(new SPARCAddress(array2, 0), tempReg2); - masm.compareBranch(tempReg1, tempReg2, NotEqual, Xcc, falseLabel, PREDICT_TAKEN, null); - } else { - masm.bind(compare1Byte); - } - } else { - masm.bind(compare2Bytes); - } - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBitManipulationOp.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.lir.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isRegister; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.PlatformKind; - -public final class SPARCBitManipulationOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCBitManipulationOp.class); - - public enum IntrinsicOpcode { - IBSR(SizeEstimate.create(13)), - LBSR(SizeEstimate.create(14)), - BSF(SizeEstimate.create(4)); - - final SizeEstimate size; - - IntrinsicOpcode(SizeEstimate size) { - this.size = size; - } - } - - @Opcode private final IntrinsicOpcode opcode; - @Def protected AllocatableValue result; - @Alive({REG}) protected AllocatableValue input; - @Temp({REG}) protected AllocatableValue scratch; - - public SPARCBitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input, LIRGeneratorTool gen) { - super(TYPE, opcode.size); - this.opcode = opcode; - this.result = result; - this.input = input; - scratch = gen.newVariable(LIRKind.combine(input)); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - Register dst = asRegister(result, WORD); - if (isRegister(input)) { - Register src = asRegister(input); - switch (opcode) { - case BSF: - PlatformKind tkind = input.getPlatformKind(); - if (tkind == WORD) { - masm.sub(src, 1, dst); - masm.andn(dst, src, dst); - masm.srl(dst, g0, dst); - masm.popc(dst, dst); - } else if (tkind == XWORD) { - masm.sub(src, 1, dst); - masm.andn(dst, src, dst); - masm.popc(dst, dst); - } else { - throw GraalError.shouldNotReachHere("missing: " + tkind); - } - break; - case IBSR: { - PlatformKind ikind = input.getPlatformKind(); - assert ikind == WORD; - Register tmp = asRegister(scratch); - assert !tmp.equals(dst); - masm.srl(src, 1, tmp); - masm.srl(src, 0, dst); - masm.or(dst, tmp, dst); - masm.srl(dst, 2, tmp); - masm.or(dst, tmp, dst); - masm.srl(dst, 4, tmp); - masm.or(dst, tmp, dst); - masm.srl(dst, 8, tmp); - masm.or(dst, tmp, dst); - masm.srl(dst, 16, tmp); - masm.or(dst, tmp, dst); - masm.popc(dst, dst); - masm.sub(dst, 1, dst); - break; - } - case LBSR: { - PlatformKind lkind = input.getPlatformKind(); - assert lkind == XWORD; - Register tmp = asRegister(scratch); - assert !tmp.equals(dst); - masm.srlx(src, 1, tmp); - masm.or(src, tmp, dst); - masm.srlx(dst, 2, tmp); - masm.or(dst, tmp, dst); - masm.srlx(dst, 4, tmp); - masm.or(dst, tmp, dst); - masm.srlx(dst, 8, tmp); - masm.or(dst, tmp, dst); - masm.srlx(dst, 16, tmp); - masm.or(dst, tmp, dst); - masm.srlx(dst, 32, tmp); - masm.or(dst, tmp, dst); - masm.popc(dst, dst); - masm.sub(dst, 1, dst); // This is required to fit the given structure. - break; - } - default: - throw GraalError.shouldNotReachHere(); - - } - } else { - throw GraalError.shouldNotReachHere(); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBlockEndOp.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.lir.sparc; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstruction; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.StandardOp.BlockEndOp; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -public abstract class SPARCBlockEndOp extends LIRInstruction implements BlockEndOp, SPARCLIRInstructionMixin { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCBlockEndOp.class); - private final SPARCLIRInstructionMixinStore store; - - protected SPARCBlockEndOp(LIRInstructionClass c) { - this(c, null); - } - - protected SPARCBlockEndOp(LIRInstructionClass c, SizeEstimate sizeEstimate) { - super(c); - store = new SPARCLIRInstructionMixinStore(sizeEstimate); - } - - @Override - public SPARCLIRInstructionMixinStore getSPARCLIRInstructionStore() { - return store; - } - - @Override - public void emitCode(CompilationResultBuilder crb) { - emitCode(crb, (SPARCMacroAssembler) crb.asm); - } - - protected abstract void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm); -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCBreakpointOp.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.lir.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; - -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.meta.Value; - -/** - * Emits a breakpoint. - */ -@Opcode("BREAKPOINT") -public final class SPARCBreakpointOp extends SPARCLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCBreakpointOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(1); - - // historical - from hotspot src/cpu/sparc/vm - // promises that the system will not use traps 16-31 - // We want to use ST_BREAKPOINT here, but the debugger is confused by it. - public static final int ST_RESERVED_FOR_USER_0 = 0x10; - - /** - * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger). - */ - @Use({REG, STACK}) protected Value[] parameters; - - public SPARCBreakpointOp(Value[] parameters) { - super(TYPE, SIZE); - this.parameters = parameters; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - masm.ta(ST_RESERVED_FOR_USER_0); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCByteSwapOp.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.lir.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.Asi; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.ValueUtil; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.sparc.SPARCKind; - -@Opcode("BSWAP") -public final class SPARCByteSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(SPARCByteSwapOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(3); - @Def({REG, HINT}) protected AllocatableValue result; - @Use({REG}) protected AllocatableValue input; - @Temp({REG}) protected AllocatableValue tempIndex; - @Use({STACK, UNINITIALIZED}) protected AllocatableValue tmpSlot; - - public SPARCByteSwapOp(LIRGeneratorTool tool, AllocatableValue result, AllocatableValue input) { - super(TYPE, SIZE); - this.result = result; - this.input = input; - this.tmpSlot = tool.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(XWORD)); - this.tempIndex = tool.newVariable(LIRKind.value(XWORD)); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - SPARCAddress addr = (SPARCAddress) crb.asAddress(tmpSlot); - SPARCMove.emitStore(input, addr, result.getPlatformKind(), SPARCDelayedControlTransfer.DUMMY, null, crb, masm); - if (addr.getIndex().equals(Register.None)) { - Register tempReg = ValueUtil.asRegister(tempIndex, XWORD); - masm.setx(addr.getDisplacement(), tempReg, false); - addr = new SPARCAddress(addr.getBase(), tempReg); - } - getDelayedControlTransfer().emitControlTransfer(crb, masm); - switch ((SPARCKind) input.getPlatformKind()) { - case WORD: - masm.lduwa(addr.getBase(), addr.getIndex(), asRegister(result, WORD), Asi.ASI_PRIMARY_LITTLE); - break; - case XWORD: - masm.ldxa(addr.getBase(), addr.getIndex(), asRegister(result, XWORD), Asi.ASI_PRIMARY_LITTLE); - break; - default: - throw GraalError.shouldNotReachHere(); - } - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCCall.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (c) 2013, 2018, 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 org.graalvm.compiler.lir.sparc; - -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.code.ValueUtil.isRegister; -import static jdk.vm.ci.sparc.SPARC.o7; - -import org.graalvm.compiler.asm.sparc.SPARCAddress; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRFrameState; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.InvokeTarget; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.Value; - -public class SPARCCall { - - public abstract static class CallOp extends SPARCLIRInstruction { - @Def({REG, ILLEGAL}) protected Value result; - @Use({REG, STACK}) protected Value[] parameters; - @Temp({REG, STACK}) protected Value[] temps; - @State protected LIRFrameState state; - - protected CallOp(LIRInstructionClass c, SizeEstimate size, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(c, size); - this.result = result; - this.parameters = parameters; - this.state = state; - this.temps = addStackSlotsToTemporaries(parameters, temps); - assert temps != null; - } - - @Override - public boolean destroysCallerSavedRegisters() { - return true; - } - } - - public abstract static class MethodCallOp extends CallOp { - - protected final ResolvedJavaMethod callTarget; - - protected MethodCallOp(LIRInstructionClass c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(c, size, result, parameters, temps, state); - this.callTarget = callTarget; - } - - } - - @Opcode("CALL_DIRECT") - public abstract static class DirectCallOp extends MethodCallOp { - private boolean emitted = false; - private int before = -1; - - public DirectCallOp(LIRInstructionClass c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(c, size, callTarget, result, parameters, temps, state); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - if (!emitted) { - emitCallPrefixCode(crb, masm); - directCall(crb, masm, callTarget, null, state); - } else { - int after = masm.position(); - if (after - before == 4) { - masm.nop(); - } else if (after - before == 8) { - // everything is fine; - } else { - GraalError.shouldNotReachHere("" + (after - before)); - } - after = masm.position(); - crb.recordDirectCall(before, after, callTarget, state); - crb.recordExceptionHandlers(after, state); - masm.ensureUniquePC(); - } - } - - @SuppressWarnings("unused") - public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - // - } - - public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - assert !emitted; - emitCallPrefixCode(crb, masm); - before = masm.call(0); - emitted = true; - } - - public void resetState() { - emitted = false; - before = -1; - } - } - - @Opcode("CALL_INDIRECT") - public abstract static class IndirectCallOp extends MethodCallOp { - @Use({REG}) protected Value targetAddress; - - protected IndirectCallOp(LIRInstructionClass c, SizeEstimate size, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, - Value targetAddress, LIRFrameState state) { - super(c, size, callTarget, result, parameters, temps, state); - this.targetAddress = targetAddress; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - indirectCall(crb, masm, asRegister(targetAddress), callTarget, state); - } - - @Override - public void verify() { - super.verify(); - assert isRegister(targetAddress) : "The current register allocator cannot handle variables to be used at call sites, it must be in a fixed register for now"; - } - } - - public abstract static class ForeignCallOp extends CallOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ForeignCallOp.class); - - protected final ForeignCallLinkage callTarget; - - public ForeignCallOp(LIRInstructionClass c, SizeEstimate size, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(c, size, result, parameters, temps, state); - this.callTarget = callTarget; - } - - @Override - public boolean destroysCallerSavedRegisters() { - return callTarget.destroysRegisters(); - } - } - - @Opcode("NEAR_FOREIGN_CALL") - public static final class DirectNearForeignCallOp extends ForeignCallOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(1); - - public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(TYPE, SIZE, linkage, result, parameters, temps, state); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - directCall(crb, masm, callTarget, null, state); - } - } - - @Opcode("FAR_FOREIGN_CALL") - public static final class DirectFarForeignCallOp extends ForeignCallOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(1); - - public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) { - super(TYPE, SIZE, callTarget, result, parameters, temps, state); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - try (ScratchRegister scratch = masm.getScratchRegister()) { - directCall(crb, masm, callTarget, scratch.getRegister(), state); - } - } - } - - public static void directCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info) { - int before; - if (scratch != null) { - // offset might not fit a 30-bit displacement, generate an - // indirect call with a 64-bit immediate - before = masm.position(); - masm.sethix(0L, scratch, true); - masm.jmpl(scratch, 0, o7); - } else { - before = masm.call(0); - } - masm.nop(); // delay slot - int after = masm.position(); - crb.recordDirectCall(before, after, callTarget, info); - crb.recordExceptionHandlers(after, info); - masm.ensureUniquePC(); - } - - public static void indirectJmp(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget target) { - int before = masm.position(); - masm.sethix(0L, dst, true); - masm.jmp(new SPARCAddress(dst, 0)); - masm.nop(); // delay slot - int after = masm.position(); - crb.recordIndirectCall(before, after, target, null); - masm.ensureUniquePC(); - } - - public static void indirectCall(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) { - int before = masm.jmpl(dst, 0, o7); - masm.nop(); // delay slot - int after = masm.position(); - crb.recordIndirectCall(before, after, callTarget, info); - crb.recordExceptionHandlers(after, info); - masm.ensureUniquePC(); - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java +++ /dev/null @@ -1,767 +0,0 @@ -/* - * Copyright (c) 2013, 2020, 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 org.graalvm.compiler.lir.sparc; - -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.CPU; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.INSTRUCTION_SIZE; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm10; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm11; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm13; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.isSimm5; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Annul.NOT_ANNUL; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_NOT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict.PREDICT_TAKEN; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Fcc0; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Icc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CC.Xcc; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Always; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Equal; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Equal; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Greater; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_GreaterOrEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_Less; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_LessOrEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedGreaterOrEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrGreater; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrLess; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.F_UnorderedOrLessOrEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Greater; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterEqualUnsigned; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.GreaterUnsigned; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.Less; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessEqualUnsigned; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.LessUnsigned; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual; -import static org.graalvm.compiler.asm.sparc.SPARCAssembler.Op3s.Subcc; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; -import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; -import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; -import static org.graalvm.compiler.lir.sparc.SPARCMove.const2reg; -import static org.graalvm.compiler.lir.sparc.SPARCOP3Op.emitOp3; - -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; - -import jdk.internal.vm.compiler.collections.EconomicMap; -import jdk.internal.vm.compiler.collections.Equivalence; -import org.graalvm.compiler.asm.Assembler; -import org.graalvm.compiler.asm.Assembler.LabelHint; -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.sparc.SPARCAssembler; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.CMOV; -import org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler; -import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister; -import org.graalvm.compiler.core.common.calc.Condition; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.LabelRef; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.StandardOp; -import org.graalvm.compiler.lir.SwitchStrategy; -import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; -import org.graalvm.compiler.lir.Variable; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; - -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.AllocatableValue; -import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; -import jdk.vm.ci.meta.PlatformKind; -import jdk.vm.ci.meta.Value; -import jdk.vm.ci.sparc.SPARC.CPUFeature; -import jdk.vm.ci.sparc.SPARCKind; - -public class SPARCControlFlow { - // This describes the maximum offset between the first emitted (load constant in to scratch, - // if does not fit into simm5 of cbcond) instruction and the final branch instruction - private static final int maximumSelfOffsetInstructions = 10; - - public static final class ReturnOp extends SPARCBlockEndOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(ReturnOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(2); - - @Use({REG, ILLEGAL}) protected Value x; - - public ReturnOp(Value x) { - super(TYPE, SIZE); - this.x = x; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - emitCodeHelper(crb, masm); - } - - public static void emitCodeHelper(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - masm.ret(); - // On SPARC we always leave the frame (in the delay slot). - crb.frameContext.leave(crb); - } - } - - public static final class CompareBranchOp extends SPARCBlockEndOp implements SPARCDelayedControlTransfer { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(CompareBranchOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(3); - static final EnumSet SUPPORTED_KINDS = EnumSet.of(XWORD, WORD); - - @Use({REG}) protected AllocatableValue x; - @Use({REG, CONST}) protected Value y; - private ConditionFlag conditionFlag; - protected final LabelRef trueDestination; - protected LabelHint trueDestinationHint; - protected final LabelRef falseDestination; - protected LabelHint falseDestinationHint; - protected final SPARCKind kind; - protected final boolean unorderedIsTrue; - private boolean emitted = false; - private int delaySlotPosition = -1; - private double trueDestinationProbability; - - public CompareBranchOp(AllocatableValue x, Value y, Condition condition, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, boolean unorderedIsTrue, - double trueDestinationProbability) { - super(TYPE, SIZE); - assert x.getPlatformKind() == y.getPlatformKind() : String.format("PlatformKind of x must match PlatformKind of y. %s!=%s", x.getPlatformKind(), y.getPlatformKind()); - this.x = x; - this.y = y; - this.trueDestination = trueDestination; - this.falseDestination = falseDestination; - this.kind = kind; - this.unorderedIsTrue = unorderedIsTrue; - this.trueDestinationProbability = trueDestinationProbability; - conditionFlag = fromCondition(kind.isInteger(), condition, unorderedIsTrue); - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - if (emitted) { // Only if delayed control transfer is used we must check this - assert masm.position() - delaySlotPosition == 4 : "Only one instruction can be stuffed into the delay slot"; - } - if (!emitted) { - requestHints(masm); - int targetPosition = getTargetPosition(masm); - if (canUseShortBranch(crb, masm, targetPosition)) { - emitted = emitShortCompareBranch(crb, masm); - } - if (!emitted) { // No short compare/branch was used, so we go into fallback - emitted = emitLongCompareBranch(crb, masm, true); - emitted = true; - } - } - assert emitted; - } - - private boolean emitLongCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm, boolean withDelayedNop) { - emitOp3(masm, Subcc, x, y); - return emitBranch(crb, masm, kind, conditionFlag, trueDestination, falseDestination, withDelayedNop, trueDestinationProbability); - } - - private static int getTargetPosition(Assembler asm) { - return asm.position() + maximumSelfOffsetInstructions * asm.target.wordSize; - } - - @Override - public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - requestHints(masm); - // When we use short branches, no delay slot is available - int targetPosition = getTargetPosition(masm); - if (!canUseShortBranch(crb, masm, targetPosition)) { - emitted = emitLongCompareBranch(crb, masm, false); - if (emitted) { - delaySlotPosition = masm.position(); - } - } - } - - private void requestHints(SPARCMacroAssembler masm) { - if (trueDestinationHint == null) { - this.trueDestinationHint = masm.requestLabelHint(trueDestination.label()); - } - if (falseDestinationHint == null) { - this.falseDestinationHint = masm.requestLabelHint(falseDestination.label()); - } - } - - /** - * Tries to use the emit the compare/branch instruction. - *

    - * CBcond has follwing limitations - *

      - *
    • Immediate field is only 5 bit and is on the right - *
    • Jump offset is maximum of -+512 instruction - * - *

      - * We get from outside - *

        - *
      • at least one of trueDestination falseDestination is within reach of +-512 - * instructions - *
      • two registers OR one register and a constant which fits simm13 - * - *

        - * We do: - *

          - *
        • find out which target needs to be branched conditionally - *
        • find out if fall-through is possible, if not, a unconditional branch is needed after - * cbcond (needJump=true) - *
        • if no fall through: we need to put the closer jump into the cbcond branch and the - * farther into the jmp (unconditional branch) - *
        • if constant on the left side, mirror to be on the right - *
        • if constant on right does not fit into simm5, put it into a scratch register - * - * @param crb - * @param masm - * @return true if the branch could be emitted - */ - private boolean emitShortCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - boolean isLong = kind == SPARCKind.XWORD; - ConditionFlag actualConditionFlag = conditionFlag; - Label actualTrueTarget = trueDestination.label(); - Label actualFalseTarget = falseDestination.label(); - Label tmpTarget; - boolean needJump; - if (crb.isSuccessorEdge(trueDestination)) { - actualConditionFlag = conditionFlag.negate(); - tmpTarget = actualTrueTarget; - actualTrueTarget = actualFalseTarget; - actualFalseTarget = tmpTarget; - needJump = false; - } else { - needJump = !crb.isSuccessorEdge(falseDestination); - int targetPosition = getTargetPosition(masm); - if (needJump && !isShortBranch(masm, targetPosition, trueDestinationHint, actualTrueTarget)) { - // we have to jump in either way, so we must put the shorter - // branch into the actualTarget as only one of the two jump targets - // is guaranteed to be simm10 - actualConditionFlag = actualConditionFlag.negate(); - tmpTarget = actualTrueTarget; - actualTrueTarget = actualFalseTarget; - actualFalseTarget = tmpTarget; - } - } - emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag, isLong); - if (needJump) { - masm.jmp(actualFalseTarget); - masm.nop(); - } - return true; - } - - private static void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag, boolean isLong) { - PlatformKind xKind = actualX.getPlatformKind(); - Register rs1 = asRegister(actualX, xKind); - if (isJavaConstant(actualY)) { - JavaConstant c = asJavaConstant(actualY); - long constantY = c.isNull() ? 0 : c.asLong(); - try (ScratchRegister scratch = masm.getScratchRegister()) { - if (SPARCMacroAssembler.isSimm5(constantY)) { - CBCOND.emit(masm, cFlag, isLong, rs1, (int) constantY, actualTrueTarget); - } else { // !simm5 - Register rs2 = scratch.getRegister(); - masm.setx(constantY, rs2, false); - CBCOND.emit(masm, cFlag, isLong, rs1, rs2, actualTrueTarget); - } - } - } else { - Register rs2 = asRegister(actualY, xKind); - CBCOND.emit(masm, cFlag, isLong, rs1, rs2, actualTrueTarget); - } - } - - private boolean canUseShortBranch(CompilationResultBuilder crb, SPARCAssembler asm, int position) { - if (!asm.hasFeature(CPUFeature.CBCOND)) { - return false; - } - if (!((SPARCKind) x.getPlatformKind()).isInteger()) { - return false; - } - // Do not use short branch, if the y value is a constant and does not fit into simm5 but - // fits into simm13; this means the code with CBcond would be longer as the code without - // CBcond. - if (isJavaConstant(y) && !isSimm5(asJavaConstant(y)) && isSimm13(asJavaConstant(y))) { - return false; - } - boolean hasShortJumpTarget = false; - if (!crb.isSuccessorEdge(trueDestination)) { - hasShortJumpTarget |= isShortBranch(asm, position, trueDestinationHint, trueDestination.label()); - } - if (!crb.isSuccessorEdge(falseDestination)) { - hasShortJumpTarget |= isShortBranch(asm, position, falseDestinationHint, falseDestination.label()); - } - return hasShortJumpTarget; - } - - @Override - public void resetState() { - emitted = false; - delaySlotPosition = -1; - } - - @Override - public void verify() { - super.verify(); - assert SUPPORTED_KINDS.contains(kind) : kind; - assert !isConstantValue(x); - assert x.getPlatformKind().equals(kind) && (isConstantValue(y) || y.getPlatformKind().equals(kind)) : x + " " + y; - } - } - - public static boolean isShortBranch(SPARCAssembler asm, int position, LabelHint hint, Label label) { - int disp = 0; - boolean dispValid = true; - if (label.isBound()) { - disp = label.position() - position; - } else if (hint != null && hint.isValid()) { - disp = hint.getTarget() - hint.getPosition(); - } else { - dispValid = false; - } - if (dispValid) { - if (disp < 0) { - disp -= maximumSelfOffsetInstructions * asm.target.wordSize; - } else { - disp += maximumSelfOffsetInstructions * asm.target.wordSize; - } - return isSimm10(disp >> 2); - } else if (hint == null) { - asm.requestLabelHint(label); - } - return false; - } - - public static final class BranchOp extends SPARCBlockEndOp implements StandardOp.BranchOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(BranchOp.class); - public static final SizeEstimate SIZE = SizeEstimate.create(2); - protected final ConditionFlag conditionFlag; - protected final LabelRef trueDestination; - protected final LabelRef falseDestination; - protected final SPARCKind kind; - protected final double trueDestinationProbability; - - public BranchOp(ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, double trueDestinationProbability) { - super(TYPE, SIZE); - this.trueDestination = trueDestination; - this.falseDestination = falseDestination; - this.kind = kind; - this.conditionFlag = conditionFlag; - this.trueDestinationProbability = trueDestinationProbability; - } - - @Override - public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - emitBranch(crb, masm, kind, conditionFlag, trueDestination, falseDestination, true, trueDestinationProbability); - } - } - - private static boolean emitBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm, SPARCKind kind, ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination, - boolean withDelayedNop, double trueDestinationProbability) { - Label actualTarget; - ConditionFlag actualConditionFlag; - boolean needJump; - BranchPredict predictTaken; - if (falseDestination != null && crb.isSuccessorEdge(trueDestination)) { - actualConditionFlag = conditionFlag != null ? conditionFlag.negate() : null; - actualTarget = falseDestination.label(); - needJump = false; - predictTaken = trueDestinationProbability < .5d ? PREDICT_TAKEN : PREDICT_NOT_TAKEN; - } else { - actualConditionFlag = conditionFlag; - actualTarget = trueDestination.label(); - needJump = falseDestination != null && !crb.isSuccessorEdge(falseDestination); - predictTaken = trueDestinationProbability > .5d ? PREDICT_TAKEN : PREDICT_NOT_TAKEN; - } - if (!withDelayedNop && needJump) { - // We cannot make use of the delay slot when we jump in true-case and false-case - return false; - } - if (kind.isFloat()) { - FBPCC.emit(masm, Fcc0, actualConditionFlag, NOT_ANNUL, predictTaken, actualTarget); - } else { - assert kind.isInteger(); - CC cc = kind.equals(WORD) ? Icc : Xcc; - BPCC.emit(masm, cc, actualConditionFlag, NOT_ANNUL, predictTaken, actualTarget); - } - if (withDelayedNop) { - masm.nop(); // delay slot - } - if (needJump) { - masm.jmp(falseDestination.label()); - } - return true; - } - - public static class StrategySwitchOp extends SPARCBlockEndOp { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(StrategySwitchOp.class); - protected Constant[] keyConstants; - private final LabelRef[] keyTargets; - private LabelRef defaultTarget; - @Alive({REG}) protected Value key; - @Alive({REG, ILLEGAL}) protected Value constantTableBase; - @Temp({REG}) protected Value scratch; - protected final SwitchStrategy strategy; - private final EconomicMap labelHints; - private final List