mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 22:19:43 +00:00
Merge
This commit is contained in:
commit
8826c8bf9f
@ -172,4 +172,5 @@ d283b82966712b353fa307845a1316da42a355f4 hs21-b10
|
||||
3aea9e9feb073f5500e031be6186666bcae89aa2 hs21-b11
|
||||
9ad1548c6b63d596c411afc35147ffd5254426d9 jdk7-b142
|
||||
9ad1548c6b63d596c411afc35147ffd5254426d9 hs21-b12
|
||||
c149193c768b8b7233da4c3a3fdc0756b975848e hs21-b13
|
||||
c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143
|
||||
|
||||
@ -1028,7 +1028,12 @@ public class CommandProcessor {
|
||||
if (AddressOps.equal(val, value)) {
|
||||
if (!printed) {
|
||||
printed = true;
|
||||
blob.printOn(out);
|
||||
try {
|
||||
blob.printOn(out);
|
||||
} catch (Exception e) {
|
||||
out.println("Exception printing blob at " + base);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
out.println("found at " + base + "\n");
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.code;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
public class AdapterBlob extends CodeBlob {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initialize(TypeDataBase db) {
|
||||
// Type type = db.lookupType("AdapterBlob");
|
||||
|
||||
// // FIXME: add any needed fields
|
||||
}
|
||||
|
||||
public AdapterBlob(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public boolean isAdapterBlob() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "AdapterBlob: " + super.getName();
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -93,6 +93,8 @@ public class CodeBlob extends VMObject {
|
||||
public boolean isUncommonTrapStub() { return false; }
|
||||
public boolean isExceptionStub() { return false; }
|
||||
public boolean isSafepointStub() { return false; }
|
||||
public boolean isRicochetBlob() { return false; }
|
||||
public boolean isAdapterBlob() { return false; }
|
||||
|
||||
// Fine grain nmethod support: isNmethod() == isJavaMethod() || isNativeMethod() || isOSRMethod()
|
||||
public boolean isJavaMethod() { return false; }
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -57,6 +57,8 @@ public class CodeCache {
|
||||
virtualConstructor.addMapping("BufferBlob", BufferBlob.class);
|
||||
virtualConstructor.addMapping("nmethod", NMethod.class);
|
||||
virtualConstructor.addMapping("RuntimeStub", RuntimeStub.class);
|
||||
virtualConstructor.addMapping("RicochetBlob", RicochetBlob.class);
|
||||
virtualConstructor.addMapping("AdapterBlob", AdapterBlob.class);
|
||||
virtualConstructor.addMapping("SafepointBlob", SafepointBlob.class);
|
||||
virtualConstructor.addMapping("DeoptimizationBlob", DeoptimizationBlob.class);
|
||||
if (VM.getVM().isServerCompiler()) {
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.code;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
/** RicochetBlob (currently only used by Compiler 2) */
|
||||
|
||||
public class RicochetBlob extends SingletonBlob {
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void initialize(TypeDataBase db) {
|
||||
// Type type = db.lookupType("RicochetBlob");
|
||||
|
||||
// FIXME: add any needed fields
|
||||
}
|
||||
|
||||
public RicochetBlob(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public boolean isRicochetBlob() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2011
|
||||
|
||||
HS_MAJOR_VER=21
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=13
|
||||
HS_BUILD_NUMBER=14
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2006, 2011, 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
|
||||
@ -33,6 +33,24 @@ else
|
||||
ZIPFLAGS=-q -y
|
||||
endif
|
||||
|
||||
jprt_build_productEmb:
|
||||
$(MAKE) JAVASE_EMBEDDED=true jprt_build_product
|
||||
|
||||
jprt_build_debugEmb:
|
||||
$(MAKE) JAVASE_EMBEDDED=true jprt_build_debug
|
||||
|
||||
jprt_build_fastdebugEmb:
|
||||
$(MAKE) JAVASE_EMBEDDED=true jprt_build_fastdebug
|
||||
|
||||
jprt_build_productOpen:
|
||||
$(MAKE) OPENJDK=true jprt_build_product
|
||||
|
||||
jprt_build_debugOpen:
|
||||
$(MAKE) OPENJDK=true jprt_build_debug
|
||||
|
||||
jprt_build_fastdebugOpen:
|
||||
$(MAKE) OPENJDK=true jprt_build_fastdebug
|
||||
|
||||
jprt_build_product: all_product copy_product_jdk export_product_jdk
|
||||
( $(CD) $(JDK_IMAGE_DIR) && \
|
||||
$(ZIPEXE) $(ZIPFLAGS) -r $(JPRT_ARCHIVE_BUNDLE) . )
|
||||
|
||||
@ -202,16 +202,21 @@ jprt.build.targets.standard= \
|
||||
${jprt.my.windows.i586}-{product|fastdebug|debug}, \
|
||||
${jprt.my.windows.x64}-{product|fastdebug|debug}
|
||||
|
||||
jprt.build.targets.open= \
|
||||
${jprt.my.solaris.i586}-{productOpen}, \
|
||||
${jprt.my.solaris.x64}-{debugOpen}, \
|
||||
${jprt.my.linux.x64}-{productOpen}
|
||||
|
||||
jprt.build.targets.embedded= \
|
||||
${jprt.my.linux.i586}-{product|fastdebug|debug}, \
|
||||
${jprt.my.linux.ppc}-{product|fastdebug}, \
|
||||
${jprt.my.linux.ppcv2}-{product|fastdebug}, \
|
||||
${jprt.my.linux.ppcsflt}-{product|fastdebug}, \
|
||||
${jprt.my.linux.armvfp}-{product|fastdebug}, \
|
||||
${jprt.my.linux.armsflt}-{product|fastdebug}
|
||||
${jprt.my.linux.i586}-{productEmb|fastdebugEmb|debugEmb}, \
|
||||
${jprt.my.linux.ppc}-{productEmb|fastdebugEmb}, \
|
||||
${jprt.my.linux.ppcv2}-{productEmb|fastdebugEmb}, \
|
||||
${jprt.my.linux.ppcsflt}-{productEmb|fastdebugEmb}, \
|
||||
${jprt.my.linux.armvfp}-{productEmb|fastdebugEmb}, \
|
||||
${jprt.my.linux.armsflt}-{productEmb|fastdebugEmb}
|
||||
|
||||
jprt.build.targets.all=${jprt.build.targets.standard}, \
|
||||
${jprt.build.targets.embedded}
|
||||
${jprt.build.targets.embedded}, ${jprt.build.targets.open}
|
||||
|
||||
jprt.build.targets.jdk7=${jprt.build.targets.all}
|
||||
jprt.build.targets.jdk7temp=${jprt.build.targets.all}
|
||||
@ -453,6 +458,12 @@ jprt.my.windows.x64.test.targets = \
|
||||
${jprt.my.windows.x64}-product-c2-jbb_G1, \
|
||||
${jprt.my.windows.x64}-product-c2-jbb_ParOldGC
|
||||
|
||||
# Some basic "smoke" tests for OpenJDK builds
|
||||
jprt.test.targets.open = \
|
||||
${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98_tiered, \
|
||||
${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98_tiered, \
|
||||
${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98_tiered
|
||||
|
||||
# Testing for actual embedded builds is different to standard
|
||||
jprt.my.linux.i586.test.targets.embedded = \
|
||||
linux_i586_2.6-product-c1-scimark
|
||||
@ -461,6 +472,7 @@ jprt.my.linux.i586.test.targets.embedded = \
|
||||
# Note: no PPC or ARM tests at this stage
|
||||
|
||||
jprt.test.targets.standard = \
|
||||
${jprt.my.linux.i586.test.targets.embedded}, \
|
||||
${jprt.my.solaris.sparc.test.targets}, \
|
||||
${jprt.my.solaris.sparcv9.test.targets}, \
|
||||
${jprt.my.solaris.i586.test.targets}, \
|
||||
@ -468,7 +480,8 @@ jprt.test.targets.standard = \
|
||||
${jprt.my.linux.i586.test.targets}, \
|
||||
${jprt.my.linux.x64.test.targets}, \
|
||||
${jprt.my.windows.i586.test.targets}, \
|
||||
${jprt.my.windows.x64.test.targets}
|
||||
${jprt.my.windows.x64.test.targets}, \
|
||||
${jprt.test.targets.open}
|
||||
|
||||
jprt.test.targets.embedded= \
|
||||
${jprt.my.linux.i586.test.targets.embedded}, \
|
||||
|
||||
@ -389,7 +389,7 @@ void MethodHandles::load_stack_move(MacroAssembler* _masm,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
#ifdef ASSERT
|
||||
void MethodHandles::RicochetFrame::verify_offsets() {
|
||||
// Check compatibility of this struct with the more generally used offsets of class frame:
|
||||
int ebp_off = sender_link_offset_in_bytes(); // offset from struct base to local rbp value
|
||||
|
||||
@ -43,7 +43,7 @@ ciMethod* ciMethodHandle::get_adapter_impl(bool is_invokedynamic) const {
|
||||
methodHandle callee(_callee->get_methodOop());
|
||||
// We catch all exceptions here that could happen in the method
|
||||
// handle compiler and stop the VM.
|
||||
MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD);
|
||||
MethodHandleCompiler mhc(h, callee->name(), callee->signature(), _profile->count(), is_invokedynamic, THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
methodHandle m = mhc.compile(THREAD);
|
||||
if (!HAS_PENDING_EXCEPTION) {
|
||||
|
||||
@ -1810,7 +1810,7 @@ public:
|
||||
void maybe_print(oop* p) {
|
||||
if (_print_nm == NULL) return;
|
||||
if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root");
|
||||
tty->print_cr(""PTR_FORMAT"[offset=%d] detected non-perm oop "PTR_FORMAT" (found at "PTR_FORMAT")",
|
||||
tty->print_cr(""PTR_FORMAT"[offset=%d] detected scavengable oop "PTR_FORMAT" (found at "PTR_FORMAT")",
|
||||
_print_nm, (int)((intptr_t)p - (intptr_t)_print_nm),
|
||||
(intptr_t)(*p), (intptr_t)p);
|
||||
(*p)->print();
|
||||
@ -2311,7 +2311,7 @@ public:
|
||||
_nm->print_nmethod(true);
|
||||
_ok = false;
|
||||
}
|
||||
tty->print_cr("*** non-perm oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
|
||||
tty->print_cr("*** scavengable oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
|
||||
(intptr_t)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
|
||||
(*p)->print();
|
||||
}
|
||||
@ -2324,7 +2324,7 @@ void nmethod::verify_scavenge_root_oops() {
|
||||
DebugScavengeRoot debug_scavenge_root(this);
|
||||
oops_do(&debug_scavenge_root);
|
||||
if (!debug_scavenge_root.ok())
|
||||
fatal("found an unadvertised bad non-perm oop in the code cache");
|
||||
fatal("found an unadvertised bad scavengable oop in the code cache");
|
||||
}
|
||||
assert(scavenge_root_not_marked(), "");
|
||||
}
|
||||
|
||||
@ -109,7 +109,7 @@ class xmlStream;
|
||||
class nmethod : public CodeBlob {
|
||||
friend class VMStructs;
|
||||
friend class NMethodSweeper;
|
||||
friend class CodeCache; // non-perm oops
|
||||
friend class CodeCache; // scavengable oops
|
||||
private:
|
||||
// Shared fields for all nmethod's
|
||||
methodOop _method;
|
||||
@ -466,17 +466,17 @@ public:
|
||||
bool is_at_poll_return(address pc);
|
||||
bool is_at_poll_or_poll_return(address pc);
|
||||
|
||||
// Non-perm oop support
|
||||
// Scavengable oop support
|
||||
bool on_scavenge_root_list() const { return (_scavenge_root_state & 1) != 0; }
|
||||
protected:
|
||||
enum { npl_on_list = 0x01, npl_marked = 0x10 };
|
||||
void set_on_scavenge_root_list() { _scavenge_root_state = npl_on_list; }
|
||||
enum { sl_on_list = 0x01, sl_marked = 0x10 };
|
||||
void set_on_scavenge_root_list() { _scavenge_root_state = sl_on_list; }
|
||||
void clear_on_scavenge_root_list() { _scavenge_root_state = 0; }
|
||||
// assertion-checking and pruning logic uses the bits of _scavenge_root_state
|
||||
#ifndef PRODUCT
|
||||
void set_scavenge_root_marked() { _scavenge_root_state |= npl_marked; }
|
||||
void clear_scavenge_root_marked() { _scavenge_root_state &= ~npl_marked; }
|
||||
bool scavenge_root_not_marked() { return (_scavenge_root_state &~ npl_on_list) == 0; }
|
||||
void set_scavenge_root_marked() { _scavenge_root_state |= sl_marked; }
|
||||
void clear_scavenge_root_marked() { _scavenge_root_state &= ~sl_marked; }
|
||||
bool scavenge_root_not_marked() { return (_scavenge_root_state &~ sl_on_list) == 0; }
|
||||
// N.B. there is no positive marked query, and we only use the not_marked query for asserts.
|
||||
#endif //PRODUCT
|
||||
nmethod* scavenge_root_link() const { return _scavenge_root_link; }
|
||||
|
||||
@ -3054,6 +3054,28 @@ void ConcurrentMark::registerCSetRegion(HeapRegion* hr) {
|
||||
_should_gray_objects = true;
|
||||
}
|
||||
|
||||
// Resets the region fields of active CMTasks whose values point
|
||||
// into the collection set.
|
||||
void ConcurrentMark::reset_active_task_region_fields_in_cset() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "should be in STW");
|
||||
assert(parallel_marking_threads() <= _max_task_num, "sanity");
|
||||
|
||||
for (int i = 0; i < (int)parallel_marking_threads(); i += 1) {
|
||||
CMTask* task = _tasks[i];
|
||||
HeapWord* task_finger = task->finger();
|
||||
if (task_finger != NULL) {
|
||||
assert(_g1h->is_in_g1_reserved(task_finger), "not in heap");
|
||||
HeapRegion* finger_region = _g1h->heap_region_containing(task_finger);
|
||||
if (finger_region->in_collection_set()) {
|
||||
// The task's current region is in the collection set.
|
||||
// This region will be evacuated in the current GC and
|
||||
// the region fields in the task will be stale.
|
||||
task->giveup_current_region();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// abandon current marking iteration due to a Full GC
|
||||
void ConcurrentMark::abort() {
|
||||
// Clear all marks to force marking thread to do nothing
|
||||
|
||||
@ -809,10 +809,19 @@ public:
|
||||
|
||||
// It indicates that a new collection set is being chosen.
|
||||
void newCSet();
|
||||
|
||||
// It registers a collection set heap region with CM. This is used
|
||||
// to determine whether any heap regions are located above the finger.
|
||||
void registerCSetRegion(HeapRegion* hr);
|
||||
|
||||
// Resets the region fields of any active CMTask whose region fields
|
||||
// are in the collection set (i.e. the region currently claimed by
|
||||
// the CMTask will be evacuated and may be used, subsequently, as
|
||||
// an alloc region). When this happens the region fields in the CMTask
|
||||
// are stale and, hence, should be cleared causing the worker thread
|
||||
// to claim a new region.
|
||||
void reset_active_task_region_fields_in_cset();
|
||||
|
||||
// Registers the maximum region-end associated with a set of
|
||||
// regions with CM. Again this is used to determine whether any
|
||||
// heap regions are located above the finger.
|
||||
@ -1039,9 +1048,6 @@ private:
|
||||
void setup_for_region(HeapRegion* hr);
|
||||
// it brings up-to-date the limit of the region
|
||||
void update_region_limit();
|
||||
// it resets the local fields after a task has finished scanning a
|
||||
// region
|
||||
void giveup_current_region();
|
||||
|
||||
// called when either the words scanned or the refs visited limit
|
||||
// has been reached
|
||||
@ -1094,6 +1100,11 @@ public:
|
||||
// exit the termination protocol after it's entered it.
|
||||
virtual bool should_exit_termination();
|
||||
|
||||
// Resets the local region fields after a task has finished scanning a
|
||||
// region; or when they have become stale as a result of the region
|
||||
// being evacuated.
|
||||
void giveup_current_region();
|
||||
|
||||
HeapWord* finger() { return _finger; }
|
||||
|
||||
bool has_aborted() { return _has_aborted; }
|
||||
|
||||
@ -428,6 +428,37 @@ void G1CollectedHeap::stop_conc_gc_threads() {
|
||||
_cmThread->stop();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// A region is added to the collection set as it is retired
|
||||
// so an address p can point to a region which will be in the
|
||||
// collection set but has not yet been retired. This method
|
||||
// therefore is only accurate during a GC pause after all
|
||||
// regions have been retired. It is used for debugging
|
||||
// to check if an nmethod has references to objects that can
|
||||
// be move during a partial collection. Though it can be
|
||||
// inaccurate, it is sufficient for G1 because the conservative
|
||||
// implementation of is_scavengable() for G1 will indicate that
|
||||
// all nmethods must be scanned during a partial collection.
|
||||
bool G1CollectedHeap::is_in_partial_collection(const void* p) {
|
||||
HeapRegion* hr = heap_region_containing(p);
|
||||
return hr != NULL && hr->in_collection_set();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns true if the reference points to an object that
|
||||
// can move in an incremental collecction.
|
||||
bool G1CollectedHeap::is_scavengable(const void* p) {
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
G1CollectorPolicy* g1p = g1h->g1_policy();
|
||||
HeapRegion* hr = heap_region_containing(p);
|
||||
if (hr == NULL) {
|
||||
// perm gen (or null)
|
||||
return false;
|
||||
} else {
|
||||
return !hr->isHumongous();
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::check_ct_logs_at_safepoint() {
|
||||
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
|
||||
CardTableModRefBS* ct_bs = (CardTableModRefBS*)barrier_set();
|
||||
@ -3292,8 +3323,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
// progress, this will be zero.
|
||||
_cm->set_oops_do_bound();
|
||||
|
||||
if (mark_in_progress())
|
||||
if (mark_in_progress()) {
|
||||
concurrent_mark()->newCSet();
|
||||
}
|
||||
|
||||
#if YOUNG_LIST_VERBOSE
|
||||
gclog_or_tty->print_cr("\nBefore choosing collection set.\nYoung_list:");
|
||||
@ -3303,6 +3335,16 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
|
||||
g1_policy()->choose_collection_set(target_pause_time_ms);
|
||||
|
||||
// We have chosen the complete collection set. If marking is
|
||||
// active then, we clear the region fields of any of the
|
||||
// concurrent marking tasks whose region fields point into
|
||||
// the collection set as these values will become stale. This
|
||||
// will cause the owning marking threads to claim a new region
|
||||
// when marking restarts.
|
||||
if (mark_in_progress()) {
|
||||
concurrent_mark()->reset_active_task_region_fields_in_cset();
|
||||
}
|
||||
|
||||
// Nothing to do if we were unable to choose a collection set.
|
||||
#if G1_REM_SET_LOGGING
|
||||
gclog_or_tty->print_cr("\nAfter pause, heap:");
|
||||
|
||||
@ -1254,6 +1254,12 @@ public:
|
||||
return hr != NULL && hr->is_young();
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
virtual bool is_in_partial_collection(const void* p);
|
||||
#endif
|
||||
|
||||
virtual bool is_scavengable(const void* addr);
|
||||
|
||||
// We don't need barriers for initializing stores to objects
|
||||
// in the young gen: for the SATB pre-barrier, there is no
|
||||
// pre-value that needs to be remembered; for the remembered-set
|
||||
|
||||
@ -339,6 +339,21 @@ bool ParallelScavengeHeap::is_in_reserved(const void* p) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParallelScavengeHeap::is_scavengable(const void* addr) {
|
||||
return is_in_young((oop)addr);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// Don't implement this by using is_in_young(). This method is used
|
||||
// in some cases to check that is_in_young() is correct.
|
||||
bool ParallelScavengeHeap::is_in_partial_collection(const void *p) {
|
||||
assert(is_in_reserved(p) || p == NULL,
|
||||
"Does not work if address is non-null and outside of the heap");
|
||||
// The order of the generations is perm (low addr), old, young (high addr)
|
||||
return p >= old_gen()->reserved().end();
|
||||
}
|
||||
#endif
|
||||
|
||||
// There are two levels of allocation policy here.
|
||||
//
|
||||
// When an allocation request fails, the requesting thread must invoke a VM
|
||||
|
||||
@ -127,6 +127,12 @@ CollectorPolicy* collector_policy() const { return (CollectorPolicy*) _collector
|
||||
// collection.
|
||||
virtual bool is_maximal_no_gc() const;
|
||||
|
||||
// Return true if the reference points to an object that
|
||||
// can be moved in a partial collection. For currently implemented
|
||||
// generational collectors that means during a collection of
|
||||
// the young gen.
|
||||
virtual bool is_scavengable(const void* addr);
|
||||
|
||||
// Does this heap support heap inspection? (+PrintClassHistogram)
|
||||
bool supports_heap_inspection() const { return true; }
|
||||
|
||||
@ -143,6 +149,10 @@ CollectorPolicy* collector_policy() const { return (CollectorPolicy*) _collector
|
||||
return perm_gen()->reserved().contains(p);
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
virtual bool is_in_partial_collection(const void *p);
|
||||
#endif
|
||||
|
||||
bool is_permanent(const void *p) const { // committed part
|
||||
return perm_gen()->is_in(p);
|
||||
}
|
||||
|
||||
@ -51,7 +51,12 @@ inline void ParallelScavengeHeap::invoke_full_gc(bool maximum_compaction)
|
||||
}
|
||||
|
||||
inline bool ParallelScavengeHeap::is_in_young(oop p) {
|
||||
return young_gen()->is_in_reserved(p);
|
||||
// Assumes the the old gen address range is lower than that of the young gen.
|
||||
const void* loc = (void*) p;
|
||||
bool result = ((HeapWord*)p) >= young_gen()->reserved().start();
|
||||
assert(result == young_gen()->is_in_reserved(p),
|
||||
err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, (void*)p));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool ParallelScavengeHeap::is_in_old_or_perm(oop p) {
|
||||
|
||||
@ -269,6 +269,13 @@ class CollectedHeap : public CHeapObj {
|
||||
// space). If you need the more conservative answer use is_permanent().
|
||||
virtual bool is_in_permanent(const void *p) const = 0;
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
// Returns true if "p" is in the part of the
|
||||
// heap being collected.
|
||||
virtual bool is_in_partial_collection(const void *p) = 0;
|
||||
#endif
|
||||
|
||||
bool is_in_permanent_or_null(const void *p) const {
|
||||
return p == NULL || is_in_permanent(p);
|
||||
}
|
||||
@ -284,11 +291,7 @@ class CollectedHeap : public CHeapObj {
|
||||
|
||||
// An object is scavengable if its location may move during a scavenge.
|
||||
// (A scavenge is a GC which is not a full GC.)
|
||||
// Currently, this just means it is not perm (and not null).
|
||||
// This could change if we rethink what's in perm-gen.
|
||||
bool is_scavengable(const void *p) const {
|
||||
return !is_in_permanent_or_null(p);
|
||||
}
|
||||
virtual bool is_scavengable(const void *p) = 0;
|
||||
|
||||
// Returns "TRUE" if "p" is a method oop in the
|
||||
// current heap, with high probability. This predicate
|
||||
|
||||
@ -203,11 +203,14 @@ void print_oop(oop value, outputStream* st) {
|
||||
if (value == NULL) {
|
||||
st->print_cr(" NULL");
|
||||
} else if (java_lang_String::is_instance(value)) {
|
||||
EXCEPTION_MARK;
|
||||
Handle h_value (THREAD, value);
|
||||
Symbol* sym = java_lang_String::as_symbol(h_value, CATCH);
|
||||
print_symbol(sym, st);
|
||||
sym->decrement_refcount();
|
||||
char buf[40];
|
||||
int len = java_lang_String::utf8_length(value);
|
||||
java_lang_String::as_utf8_string(value, buf, sizeof(buf));
|
||||
if (len >= (int)sizeof(buf)) {
|
||||
st->print_cr(" %s...[%d]", buf, len);
|
||||
} else {
|
||||
st->print_cr(" %s", buf);
|
||||
}
|
||||
} else {
|
||||
st->print_cr(" " PTR_FORMAT, (intptr_t) value);
|
||||
}
|
||||
|
||||
@ -711,15 +711,6 @@ void GenCollectedHeap::set_par_threads(int t) {
|
||||
_gen_process_strong_tasks->set_n_threads(t);
|
||||
}
|
||||
|
||||
class AssertIsPermClosure: public OopClosure {
|
||||
public:
|
||||
void do_oop(oop* p) {
|
||||
assert((*p) == NULL || (*p)->is_perm(), "Referent should be perm.");
|
||||
}
|
||||
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
|
||||
};
|
||||
static AssertIsPermClosure assert_is_perm_closure;
|
||||
|
||||
void GenCollectedHeap::
|
||||
gen_process_strong_roots(int level,
|
||||
bool younger_gens_as_roots,
|
||||
@ -962,6 +953,13 @@ void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs,
|
||||
}
|
||||
}
|
||||
|
||||
bool GenCollectedHeap::is_in_young(oop p) {
|
||||
bool result = ((HeapWord*)p) < _gens[_n_gens - 1]->reserved().start();
|
||||
assert(result == _gens[0]->is_in_reserved(p),
|
||||
err_msg("incorrect test - result=%d, p=" PTR_FORMAT, result, (void*)p));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns "TRUE" iff "p" points into the allocated area of the heap.
|
||||
bool GenCollectedHeap::is_in(const void* p) const {
|
||||
#ifndef ASSERT
|
||||
@ -984,10 +982,16 @@ bool GenCollectedHeap::is_in(const void* p) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns "TRUE" iff "p" points into the allocated area of the heap.
|
||||
bool GenCollectedHeap::is_in_youngest(void* p) {
|
||||
return _gens[0]->is_in(p);
|
||||
#ifdef ASSERT
|
||||
// Don't implement this by using is_in_young(). This method is used
|
||||
// in some cases to check that is_in_young() is correct.
|
||||
bool GenCollectedHeap::is_in_partial_collection(const void* p) {
|
||||
assert(is_in_reserved(p) || p == NULL,
|
||||
"Does not work if address is non-null and outside of the heap");
|
||||
// The order of the generations is young (low addr), old, perm (high addr)
|
||||
return p < _gens[_n_gens - 2]->reserved().end() && p != NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
void GenCollectedHeap::oop_iterate(OopClosure* cl) {
|
||||
for (int i = 0; i < _n_gens; i++) {
|
||||
|
||||
@ -216,8 +216,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Returns "TRUE" iff "p" points into the youngest generation.
|
||||
bool is_in_youngest(void* p);
|
||||
// Returns true if the reference is to an object in the reserved space
|
||||
// for the young generation.
|
||||
// Assumes the the young gen address range is less than that of the old gen.
|
||||
bool is_in_young(oop p);
|
||||
|
||||
#ifdef ASSERT
|
||||
virtual bool is_in_partial_collection(const void* p);
|
||||
#endif
|
||||
|
||||
virtual bool is_scavengable(const void* addr) {
|
||||
return is_in_young((oop)addr);
|
||||
}
|
||||
|
||||
// Iteration functions.
|
||||
void oop_iterate(OopClosure* cl);
|
||||
@ -283,7 +293,7 @@ public:
|
||||
// "Check can_elide_initializing_store_barrier() for this collector");
|
||||
// but unfortunately the flag UseSerialGC need not necessarily always
|
||||
// be set when DefNew+Tenured are being used.
|
||||
return is_in_youngest((void*)new_obj);
|
||||
return is_in_young(new_obj);
|
||||
}
|
||||
|
||||
// Can a compiler elide a store barrier when it writes
|
||||
|
||||
@ -102,6 +102,17 @@ public:
|
||||
};
|
||||
static AssertIsPermClosure assert_is_perm_closure;
|
||||
|
||||
#ifdef ASSERT
|
||||
class AssertNonScavengableClosure: public OopClosure {
|
||||
public:
|
||||
virtual void do_oop(oop* p) {
|
||||
assert(!Universe::heap()->is_in_partial_collection(*p),
|
||||
"Referent should not be scavengable."); }
|
||||
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
|
||||
};
|
||||
static AssertNonScavengableClosure assert_is_non_scavengable_closure;
|
||||
#endif
|
||||
|
||||
void SharedHeap::change_strong_roots_parity() {
|
||||
// Also set the new collection parity.
|
||||
assert(_strong_roots_parity >= 0 && _strong_roots_parity <= 2,
|
||||
@ -196,9 +207,10 @@ void SharedHeap::process_strong_roots(bool activate_scope,
|
||||
CodeCache::scavenge_root_nmethods_do(code_roots);
|
||||
}
|
||||
}
|
||||
// Verify if the code cache contents are in the perm gen
|
||||
NOT_PRODUCT(CodeBlobToOopClosure assert_code_is_perm(&assert_is_perm_closure, /*do_marking=*/ false));
|
||||
NOT_PRODUCT(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_perm));
|
||||
// Verify that the code cache contents are not subject to
|
||||
// movement by a scavenging collection.
|
||||
DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, /*do_marking=*/ false));
|
||||
DEBUG_ONLY(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable));
|
||||
}
|
||||
|
||||
if (!collecting_perm_gen) {
|
||||
|
||||
@ -397,7 +397,7 @@ void instanceRefKlass::oop_verify_on(oop obj, outputStream* st) {
|
||||
|
||||
if (referent != NULL) {
|
||||
guarantee(referent->is_oop(), "referent field heap failed");
|
||||
if (gch != NULL && !gch->is_in_youngest(obj)) {
|
||||
if (gch != NULL && !gch->is_in_young(obj)) {
|
||||
// We do a specific remembered set check here since the referent
|
||||
// field is not part of the oop mask and therefore skipped by the
|
||||
// regular verify code.
|
||||
@ -415,7 +415,7 @@ void instanceRefKlass::oop_verify_on(oop obj, outputStream* st) {
|
||||
if (next != NULL) {
|
||||
guarantee(next->is_oop(), "next field verify failed");
|
||||
guarantee(next->is_instanceRef(), "next field verify failed");
|
||||
if (gch != NULL && !gch->is_in_youngest(obj)) {
|
||||
if (gch != NULL && !gch->is_in_young(obj)) {
|
||||
// We do a specific remembered set check here since the next field is
|
||||
// not part of the oop mask and therefore skipped by the regular
|
||||
// verify code.
|
||||
|
||||
@ -615,6 +615,7 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (node->debug_orig() != NULL) {
|
||||
stringStream dorigStream;
|
||||
Node* dorig = node->debug_orig();
|
||||
@ -629,6 +630,7 @@ void IdealGraphPrinter::visit_node(Node *n, void *param) {
|
||||
}
|
||||
print_prop("debug_orig", dorigStream.as_string());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_chaitin && _chaitin != (PhaseChaitin *)0xdeadbeef) {
|
||||
buffer[0] = 0;
|
||||
|
||||
@ -1453,6 +1453,23 @@ bool IdealLoopTree::dominates_backedge(Node* ctrl) {
|
||||
return _phase->dom_lca_internal(ctrl, backedge) == ctrl;
|
||||
}
|
||||
|
||||
//------------------------------adjust_limit-----------------------------------
|
||||
// Helper function for add_constraint().
|
||||
Node* PhaseIdealLoop::adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl) {
|
||||
// Compute "I :: (limit-offset)/scale"
|
||||
Node *con = new (C, 3) SubINode(rc_limit, offset);
|
||||
register_new_node(con, pre_ctrl);
|
||||
Node *X = new (C, 3) DivINode(0, con, scale);
|
||||
register_new_node(X, pre_ctrl);
|
||||
|
||||
// Adjust loop limit
|
||||
loop_limit = (stride_con > 0)
|
||||
? (Node*)(new (C, 3) MinINode(loop_limit, X))
|
||||
: (Node*)(new (C, 3) MaxINode(loop_limit, X));
|
||||
register_new_node(loop_limit, pre_ctrl);
|
||||
return loop_limit;
|
||||
}
|
||||
|
||||
//------------------------------add_constraint---------------------------------
|
||||
// Constrain the main loop iterations so the conditions:
|
||||
// low_limit <= scale_con * I + offset < upper_limit
|
||||
@ -1469,7 +1486,11 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset
|
||||
// pre-loop must check for underflow and the post-loop for overflow.
|
||||
// Negative stride*scale reverses this; pre-loop checks for overflow and
|
||||
// post-loop for underflow.
|
||||
if (stride_con*scale_con > 0) {
|
||||
|
||||
Node *scale = _igvn.intcon(scale_con);
|
||||
set_ctrl(scale, C->root());
|
||||
|
||||
if ((stride_con^scale_con) >= 0) { // Use XOR to avoid overflow
|
||||
// The overflow limit: scale*I+offset < upper_limit
|
||||
// For main-loop compute
|
||||
// ( if (scale > 0) /* and stride > 0 */
|
||||
@ -1478,23 +1499,10 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset
|
||||
// I > (upper_limit-offset)/scale
|
||||
// )
|
||||
//
|
||||
// (upper_limit-offset) may overflow when offset < 0.
|
||||
// (upper_limit-offset) may overflow or underflow.
|
||||
// But it is fine since main loop will either have
|
||||
// less iterations or will be skipped in such case.
|
||||
Node *con = new (C, 3) SubINode(upper_limit, offset);
|
||||
register_new_node(con, pre_ctrl);
|
||||
Node *scale = _igvn.intcon(scale_con);
|
||||
set_ctrl(scale, C->root());
|
||||
Node *X = new (C, 3) DivINode(0, con, scale);
|
||||
register_new_node(X, pre_ctrl);
|
||||
|
||||
// Adjust main-loop last iteration
|
||||
Node *loop_limit = *main_limit;
|
||||
loop_limit = (stride_con > 0) // scale > 0
|
||||
? (Node*)(new (C, 3) MinINode(loop_limit, X))
|
||||
: (Node*)(new (C, 3) MaxINode(loop_limit, X));
|
||||
register_new_node(loop_limit, pre_ctrl);
|
||||
*main_limit = loop_limit;
|
||||
*main_limit = adjust_limit(stride_con, scale, offset, upper_limit, *main_limit, pre_ctrl);
|
||||
|
||||
// The underflow limit: low_limit <= scale*I+offset.
|
||||
// For pre-loop compute
|
||||
@ -1509,76 +1517,33 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset
|
||||
if (low_limit->get_int() == -max_jint) {
|
||||
if (!RangeLimitCheck) return;
|
||||
// We need this guard when scale*pre_limit+offset >= limit
|
||||
// due to underflow so we need execute pre-loop until
|
||||
// scale*I+offset >= min_int. But (low_limit-offset) will
|
||||
// underflow when offset > 0 and X will be > original_limit.
|
||||
// To avoid it we replace offset = offset > 0 ? 0 : offset
|
||||
// and add min(pre_limit, original_limit).
|
||||
// due to underflow. So we need execute pre-loop until
|
||||
// scale*I+offset >= min_int. But (min_int-offset) will
|
||||
// underflow when offset > 0 and X will be > original_limit
|
||||
// when stride > 0. To avoid it we replace positive offset with 0.
|
||||
//
|
||||
// Also (min_int+1 == -max_int) is used instead of min_int here
|
||||
// to avoid problem with scale == -1 (min_int/(-1) == min_int).
|
||||
Node* shift = _igvn.intcon(31);
|
||||
set_ctrl(shift, C->root());
|
||||
Node *neg_off = new (C, 3) RShiftINode(offset, shift);
|
||||
register_new_node(neg_off, pre_ctrl);
|
||||
offset = new (C, 3) AndINode(offset, neg_off);
|
||||
Node* sign = new (C, 3) RShiftINode(offset, shift);
|
||||
register_new_node(sign, pre_ctrl);
|
||||
offset = new (C, 3) AndINode(offset, sign);
|
||||
register_new_node(offset, pre_ctrl);
|
||||
} else {
|
||||
assert(low_limit->get_int() == 0, "wrong low limit for range check");
|
||||
// The only problem we have here when offset == min_int
|
||||
// since (0-min_int) == min_int. It may be fine for scale > 0
|
||||
// but for scale < 0 X will be < original_limit.
|
||||
// since (0-min_int) == min_int. It may be fine for stride > 0
|
||||
// but for stride < 0 X will be < original_limit. To avoid it
|
||||
// max(pre_limit, original_limit) is used in do_range_check().
|
||||
}
|
||||
con = new (C, 3) SubINode(low_limit, offset);
|
||||
register_new_node(con, pre_ctrl);
|
||||
scale = _igvn.intcon(scale_con);
|
||||
set_ctrl(scale, C->root());
|
||||
X = new (C, 3) DivINode(0, con, scale);
|
||||
register_new_node(X, pre_ctrl);
|
||||
|
||||
// Adjust pre-loop last iteration
|
||||
loop_limit = *pre_limit;
|
||||
loop_limit = (stride_con > 0) // scale > 0
|
||||
? (Node*)(new (C, 3) MaxINode(loop_limit, X))
|
||||
: (Node*)(new (C, 3) MinINode(loop_limit, X));
|
||||
register_new_node( loop_limit, pre_ctrl );
|
||||
*pre_limit = loop_limit;
|
||||
// Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond);
|
||||
*pre_limit = adjust_limit((-stride_con), scale, offset, low_limit, *pre_limit, pre_ctrl);
|
||||
|
||||
} else { // stride_con*scale_con < 0
|
||||
// For negative stride*scale pre-loop checks for overflow and
|
||||
// post-loop for underflow.
|
||||
//
|
||||
// The underflow limit: low_limit <= scale*I+offset.
|
||||
// For main-loop compute
|
||||
// scale*I+offset+1 > low_limit
|
||||
// ( if (scale < 0) /* and stride > 0 */
|
||||
// I < (low_limit-(offset+1))/scale
|
||||
// else /* scale < 0 and stride < 0 */
|
||||
// I > (low_limit-(offset+1))/scale
|
||||
// )
|
||||
|
||||
if (low_limit->get_int() == -max_jint) {
|
||||
if (!RangeLimitCheck) return;
|
||||
} else {
|
||||
assert(low_limit->get_int() == 0, "wrong low limit for range check");
|
||||
}
|
||||
|
||||
Node *one = _igvn.intcon(1);
|
||||
set_ctrl(one, C->root());
|
||||
Node *plus_one = new (C, 3) AddINode(offset, one);
|
||||
register_new_node( plus_one, pre_ctrl );
|
||||
Node *con = new (C, 3) SubINode(low_limit, plus_one);
|
||||
register_new_node(con, pre_ctrl);
|
||||
Node *scale = _igvn.intcon(scale_con);
|
||||
set_ctrl(scale, C->root());
|
||||
Node *X = new (C, 3) DivINode(0, con, scale);
|
||||
register_new_node(X, pre_ctrl);
|
||||
|
||||
// Adjust main-loop last iteration
|
||||
Node *loop_limit = *main_limit;
|
||||
loop_limit = (stride_con > 0) // scale < 0
|
||||
? (Node*)(new (C, 3) MinINode(loop_limit, X))
|
||||
: (Node*)(new (C, 3) MaxINode(loop_limit, X));
|
||||
register_new_node(loop_limit, pre_ctrl);
|
||||
*main_limit = loop_limit;
|
||||
|
||||
// The overflow limit: scale*I+offset < upper_limit
|
||||
// For pre-loop compute
|
||||
// NOT(scale*I+offset < upper_limit)
|
||||
@ -1586,26 +1551,55 @@ void PhaseIdealLoop::add_constraint( int stride_con, int scale_con, Node *offset
|
||||
// scale*I+offset+1 > upper_limit
|
||||
// ( if (scale < 0) /* and stride > 0 */
|
||||
// I < (upper_limit-(offset+1))/scale
|
||||
// else /* scale < 0 and stride < 0 */
|
||||
// else /* scale > 0 and stride < 0 */
|
||||
// I > (upper_limit-(offset+1))/scale
|
||||
// )
|
||||
plus_one = new (C, 3) AddINode(offset, one);
|
||||
//
|
||||
// (upper_limit-offset-1) may underflow or overflow.
|
||||
// To avoid it min(pre_limit, original_limit) is used
|
||||
// in do_range_check() for stride > 0 and max() for < 0.
|
||||
Node *one = _igvn.intcon(1);
|
||||
set_ctrl(one, C->root());
|
||||
|
||||
Node *plus_one = new (C, 3) AddINode(offset, one);
|
||||
register_new_node( plus_one, pre_ctrl );
|
||||
con = new (C, 3) SubINode(upper_limit, plus_one);
|
||||
register_new_node(con, pre_ctrl);
|
||||
scale = _igvn.intcon(scale_con);
|
||||
set_ctrl(scale, C->root());
|
||||
X = new (C, 3) DivINode(0, con, scale);
|
||||
register_new_node(X, pre_ctrl);
|
||||
// Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond);
|
||||
*pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl);
|
||||
|
||||
// Adjust pre-loop last iteration
|
||||
loop_limit = *pre_limit;
|
||||
loop_limit = (stride_con > 0) // scale < 0
|
||||
? (Node*)(new (C, 3) MaxINode(loop_limit, X))
|
||||
: (Node*)(new (C, 3) MinINode(loop_limit, X));
|
||||
register_new_node( loop_limit, pre_ctrl );
|
||||
*pre_limit = loop_limit;
|
||||
if (low_limit->get_int() == -max_jint) {
|
||||
if (!RangeLimitCheck) return;
|
||||
// We need this guard when scale*main_limit+offset >= limit
|
||||
// due to underflow. So we need execute main-loop while
|
||||
// scale*I+offset+1 > min_int. But (min_int-offset-1) will
|
||||
// underflow when (offset+1) > 0 and X will be < main_limit
|
||||
// when scale < 0 (and stride > 0). To avoid it we replace
|
||||
// positive (offset+1) with 0.
|
||||
//
|
||||
// Also (min_int+1 == -max_int) is used instead of min_int here
|
||||
// to avoid problem with scale == -1 (min_int/(-1) == min_int).
|
||||
Node* shift = _igvn.intcon(31);
|
||||
set_ctrl(shift, C->root());
|
||||
Node* sign = new (C, 3) RShiftINode(plus_one, shift);
|
||||
register_new_node(sign, pre_ctrl);
|
||||
plus_one = new (C, 3) AndINode(plus_one, sign);
|
||||
register_new_node(plus_one, pre_ctrl);
|
||||
} else {
|
||||
assert(low_limit->get_int() == 0, "wrong low limit for range check");
|
||||
// The only problem we have here when offset == max_int
|
||||
// since (max_int+1) == min_int and (0-min_int) == min_int.
|
||||
// But it is fine since main loop will either have
|
||||
// less iterations or will be skipped in such case.
|
||||
}
|
||||
// The underflow limit: low_limit <= scale*I+offset.
|
||||
// For main-loop compute
|
||||
// scale*I+offset+1 > low_limit
|
||||
// ( if (scale < 0) /* and stride > 0 */
|
||||
// I < (low_limit-(offset+1))/scale
|
||||
// else /* scale > 0 and stride < 0 */
|
||||
// I > (low_limit-(offset+1))/scale
|
||||
// )
|
||||
|
||||
*main_limit = adjust_limit(stride_con, scale, plus_one, low_limit, *main_limit, pre_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1869,13 +1863,8 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
// The underflow and overflow limits: 0 <= scale*I+offset < limit
|
||||
add_constraint( stride_con, scale_con, offset, zero, limit, pre_ctrl, &pre_limit, &main_limit );
|
||||
if (!conditional_rc) {
|
||||
conditional_rc = !loop->dominates_backedge(iff);
|
||||
// It is also needed if offset->_lo == min_int since
|
||||
// (0-min_int) == min_int. It may be fine for stride > 0
|
||||
// but for stride < 0 pre_limit will be < original_limit.
|
||||
const TypeInt* offset_t = _igvn.type(offset)->is_int();
|
||||
conditional_rc |= RangeLimitCheck && (offset_t->_lo == min_jint) &&
|
||||
(scale_con<0) && (stride_con<0);
|
||||
// (0-offset)/scale could be outside of loop iterations range.
|
||||
conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck;
|
||||
}
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
@ -1905,16 +1894,14 @@ void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
// Fall into LT case
|
||||
case BoolTest::lt:
|
||||
// The underflow and overflow limits: MIN_INT <= scale*I+offset < limit
|
||||
// Note: (MIN_INT+1 == -MAX_INT) is used instead of MIN_INT here
|
||||
// to avoid problem with scale == -1: MIN_INT/(-1) == MIN_INT.
|
||||
add_constraint( stride_con, scale_con, offset, mini, limit, pre_ctrl, &pre_limit, &main_limit );
|
||||
if (!conditional_rc) {
|
||||
conditional_rc = !loop->dominates_backedge(iff);
|
||||
// It is also needed if scale*pre_limit+offset >= limit
|
||||
// due to underflow so we need execute pre-loop until
|
||||
// scale*I+offset >= min_int. But (low_limit-offset) will
|
||||
// underflow when offset > 0 and X will be > original_limit.
|
||||
const TypeInt* offset_t = _igvn.type(offset)->is_int();
|
||||
conditional_rc |= RangeLimitCheck && (offset_t->_hi > 0) &&
|
||||
(scale_con>0) && (stride_con>0);
|
||||
// ((MIN_INT+1)-offset)/scale could be outside of loop iterations range.
|
||||
// Note: negative offset is replaced with 0 but (MIN_INT+1)/scale could
|
||||
// still be outside of loop range.
|
||||
conditional_rc = !loop->dominates_backedge(iff) || RangeLimitCheck;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@ -932,6 +932,8 @@ public:
|
||||
// the pre-loop or the post-loop until the condition holds true in the main
|
||||
// loop. Scale_con, offset and limit are all loop invariant.
|
||||
void add_constraint( int stride_con, int scale_con, Node *offset, Node *low_limit, Node *upper_limit, Node *pre_ctrl, Node **pre_limit, Node **main_limit );
|
||||
// Helper function for add_constraint().
|
||||
Node* adjust_limit( int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl );
|
||||
|
||||
// Partially peel loop up through last_peel node.
|
||||
bool partial_peel( IdealLoopTree *loop, Node_List &old_new );
|
||||
|
||||
@ -265,7 +265,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
assert(dest == arg_state->_type, "");
|
||||
ArgToken arg = arg_state->_arg;
|
||||
ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty));
|
||||
assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index");
|
||||
assert(!arg.has_index() || arg.index() == new_arg.index(), "should be the same index");
|
||||
debug_only(dest_klass = (klassOop)badOop);
|
||||
break;
|
||||
}
|
||||
@ -423,6 +423,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
arglist[1+i] = arg;
|
||||
if (!retain_original_args)
|
||||
change_argument(arg_type, slot, T_VOID, ArgToken(tt_void));
|
||||
i++;
|
||||
}
|
||||
arglist[1+argc] = ArgToken(); // sentinel
|
||||
oop invoker = java_lang_invoke_MethodTypeForm::vmlayout(
|
||||
@ -442,8 +443,10 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
ret = make_conversion(T_OBJECT, rklass, Bytecodes::_checkcast, ret, CHECK_(empty));
|
||||
}
|
||||
}
|
||||
int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0);
|
||||
change_argument(T_VOID, ret_slot, rtype, ret);
|
||||
if (rtype != T_VOID) {
|
||||
int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0);
|
||||
change_argument(T_VOID, ret_slot, rtype, ret);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -487,7 +490,7 @@ MethodHandleWalker::walk(TRAPS) {
|
||||
arglist[1] = length_arg; // length to check
|
||||
arglist[2] = ArgToken(); // sentinel
|
||||
make_invoke(NULL, vmIntrinsics::_checkSpreadArgument,
|
||||
Bytecodes::_invokestatic, false, 3, &arglist[0], CHECK_(empty));
|
||||
Bytecodes::_invokestatic, false, 2, &arglist[0], CHECK_(empty));
|
||||
|
||||
// Spread out the array elements.
|
||||
Bytecodes::Code aload_op = Bytecodes::_nop;
|
||||
@ -689,9 +692,8 @@ void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, boo
|
||||
// -----------------------------------------------------------------------------
|
||||
// MethodHandleCompiler
|
||||
|
||||
MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS)
|
||||
MethodHandleCompiler::MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool is_invokedynamic, TRAPS)
|
||||
: MethodHandleWalker(root, is_invokedynamic, THREAD),
|
||||
_callee(callee),
|
||||
_invoke_count(invoke_count),
|
||||
_thread(THREAD),
|
||||
_bytecode(THREAD, 50),
|
||||
@ -705,8 +707,8 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int
|
||||
(void) _constants.append(NULL);
|
||||
|
||||
// Set name and signature index.
|
||||
_name_index = cpool_symbol_put(_callee->name());
|
||||
_signature_index = cpool_symbol_put(_callee->signature());
|
||||
_name_index = cpool_symbol_put(name);
|
||||
_signature_index = cpool_symbol_put(signature);
|
||||
|
||||
// Get return type klass.
|
||||
Handle first_mtype(THREAD, chain().method_type_oop());
|
||||
@ -714,7 +716,8 @@ MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int
|
||||
_rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(first_mtype()), &_rklass);
|
||||
if (_rtype == T_ARRAY) _rtype = T_OBJECT;
|
||||
|
||||
int params = _callee->size_of_parameters(); // Incoming arguments plus receiver.
|
||||
ArgumentSizeComputer args(signature);
|
||||
int params = args.size() + 1; // Incoming arguments plus receiver.
|
||||
_num_params = for_invokedynamic() ? params - 1 : params; // XXX Check if callee is static?
|
||||
}
|
||||
|
||||
@ -732,7 +735,7 @@ methodHandle MethodHandleCompiler::compile(TRAPS) {
|
||||
}
|
||||
|
||||
|
||||
void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index, int args_size) {
|
||||
Bytecodes::check(op); // Are we legal?
|
||||
|
||||
switch (op) {
|
||||
@ -808,6 +811,14 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_d2i:
|
||||
case Bytecodes::_d2l:
|
||||
case Bytecodes::_d2f:
|
||||
case Bytecodes::_iaload:
|
||||
case Bytecodes::_laload:
|
||||
case Bytecodes::_faload:
|
||||
case Bytecodes::_daload:
|
||||
case Bytecodes::_aaload:
|
||||
case Bytecodes::_baload:
|
||||
case Bytecodes::_caload:
|
||||
case Bytecodes::_saload:
|
||||
case Bytecodes::_ireturn:
|
||||
case Bytecodes::_lreturn:
|
||||
case Bytecodes::_freturn:
|
||||
@ -821,9 +832,14 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
// bi
|
||||
case Bytecodes::_ldc:
|
||||
assert(Bytecodes::format_bits(op, false) == (Bytecodes::_fmt_b|Bytecodes::_fmt_has_k), "wrong bytecode format");
|
||||
assert((char) index == index, "index does not fit in 8-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
if (index == (index & 0xff)) {
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
} else {
|
||||
_bytecode.push(Bytecodes::_ldc_w);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
}
|
||||
break;
|
||||
|
||||
case Bytecodes::_iload:
|
||||
@ -837,9 +853,16 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_dstore:
|
||||
case Bytecodes::_astore:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bi, "wrong bytecode format");
|
||||
assert((char) index == index, "index does not fit in 8-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
if (index == (index & 0xff)) {
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index);
|
||||
} else {
|
||||
// doesn't fit in a u2
|
||||
_bytecode.push(Bytecodes::_wide);
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
}
|
||||
break;
|
||||
|
||||
// bkk
|
||||
@ -847,7 +870,7 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_ldc2_w:
|
||||
case Bytecodes::_checkcast:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bkk, "wrong bytecode format");
|
||||
assert((short) index == index, "index does not fit in 16-bit");
|
||||
assert((unsigned short) index == index, "index does not fit in 16-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
@ -858,12 +881,23 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
|
||||
case Bytecodes::_invokespecial:
|
||||
case Bytecodes::_invokevirtual:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format");
|
||||
assert((short) index == index, "index does not fit in 16-bit");
|
||||
assert((unsigned short) index == index, "index does not fit in 16-bit");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
break;
|
||||
|
||||
case Bytecodes::_invokeinterface:
|
||||
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bJJ, "wrong bytecode format");
|
||||
assert((unsigned short) index == index, "index does not fit in 16-bit");
|
||||
assert(args_size > 0, "valid args_size");
|
||||
_bytecode.push(op);
|
||||
_bytecode.push(index >> 8);
|
||||
_bytecode.push(index);
|
||||
_bytecode.push(args_size);
|
||||
_bytecode.push(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -982,7 +1016,8 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
|
||||
const ArgToken& src, TRAPS) {
|
||||
|
||||
BasicType srctype = src.basic_type();
|
||||
int index = src.index();
|
||||
TokenType tt = src.token_type();
|
||||
int index = -1;
|
||||
|
||||
switch (op) {
|
||||
case Bytecodes::_i2l:
|
||||
@ -1003,18 +1038,31 @@ MethodHandleCompiler::make_conversion(BasicType type, klassOop tk, Bytecodes::Co
|
||||
case Bytecodes::_d2i:
|
||||
case Bytecodes::_d2l:
|
||||
case Bytecodes::_d2f:
|
||||
emit_load(srctype, index);
|
||||
if (tt == tt_constant) {
|
||||
emit_load_constant(src);
|
||||
} else {
|
||||
emit_load(srctype, src.index());
|
||||
}
|
||||
stack_pop(srctype); // pop the src type
|
||||
emit_bc(op);
|
||||
stack_push(type); // push the dest value
|
||||
if (srctype != type)
|
||||
if (tt != tt_constant)
|
||||
index = src.index();
|
||||
if (srctype != type || index == -1)
|
||||
index = new_local_index(type);
|
||||
emit_store(type, index);
|
||||
break;
|
||||
|
||||
case Bytecodes::_checkcast:
|
||||
emit_load(srctype, index);
|
||||
if (tt == tt_constant) {
|
||||
emit_load_constant(src);
|
||||
} else {
|
||||
emit_load(srctype, src.index());
|
||||
index = src.index();
|
||||
}
|
||||
emit_bc(op, cpool_klass_put(tk));
|
||||
if (index == -1)
|
||||
index = new_local_index(type);
|
||||
emit_store(srctype, index);
|
||||
break;
|
||||
|
||||
@ -1057,6 +1105,11 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
Symbol* name = m->name();
|
||||
Symbol* signature = m->signature();
|
||||
|
||||
// Count the number of arguments, not the size
|
||||
ArgumentCount asc(signature);
|
||||
assert(argc == asc.size() + ((op == Bytecodes::_invokestatic || op == Bytecodes::_invokedynamic) ? 0 : 1),
|
||||
"argc mismatch");
|
||||
|
||||
if (tailcall) {
|
||||
// Actually, in order to make these methods more recognizable,
|
||||
// let's put them in holder class MethodHandle. That way stack
|
||||
@ -1105,9 +1158,13 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
case Bytecodes::_invokevirtual:
|
||||
emit_bc(op, methodref_index);
|
||||
break;
|
||||
case Bytecodes::_invokeinterface:
|
||||
Unimplemented();
|
||||
|
||||
case Bytecodes::_invokeinterface: {
|
||||
ArgumentSizeComputer asc(signature);
|
||||
emit_bc(op, methodref_index, asc.size() + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -1116,6 +1173,7 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
// Otherwise, make a recursive call to some helper routine.
|
||||
BasicType rbt = m->result_type();
|
||||
if (rbt == T_ARRAY) rbt = T_OBJECT;
|
||||
stack_push(rbt); // The return value is already pushed onto the stack.
|
||||
ArgToken ret;
|
||||
if (tailcall) {
|
||||
if (rbt != _rtype) {
|
||||
@ -1170,7 +1228,6 @@ MethodHandleCompiler::make_invoke(methodOop m, vmIntrinsics::ID iid,
|
||||
ret = ArgToken(); // Dummy return value.
|
||||
}
|
||||
else {
|
||||
stack_push(rbt); // The return value is already pushed onto the stack.
|
||||
int index = new_local_index(rbt);
|
||||
switch (rbt) {
|
||||
case T_BOOLEAN: case T_BYTE: case T_CHAR: case T_SHORT:
|
||||
@ -1195,8 +1252,32 @@ MethodHandleCompiler::make_fetch(BasicType type, klassOop tk, Bytecodes::Code op
|
||||
const MethodHandleWalker::ArgToken& base,
|
||||
const MethodHandleWalker::ArgToken& offset,
|
||||
TRAPS) {
|
||||
Unimplemented();
|
||||
return ArgToken();
|
||||
switch (base.token_type()) {
|
||||
case tt_parameter:
|
||||
case tt_temporary:
|
||||
emit_load(base.basic_type(), base.index());
|
||||
break;
|
||||
case tt_constant:
|
||||
emit_load_constant(base);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
switch (offset.token_type()) {
|
||||
case tt_parameter:
|
||||
case tt_temporary:
|
||||
emit_load(offset.basic_type(), offset.index());
|
||||
break;
|
||||
case tt_constant:
|
||||
emit_load_constant(offset);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
emit_bc(op);
|
||||
int index = new_local_index(type);
|
||||
emit_store(type, index);
|
||||
return ArgToken(tt_temporary, type, index);
|
||||
}
|
||||
|
||||
|
||||
@ -1371,12 +1452,10 @@ private:
|
||||
return s;
|
||||
}
|
||||
ArgToken token(const char* str) {
|
||||
jvalue string_con;
|
||||
string_con.j = (intptr_t) str;
|
||||
return ArgToken(tt_symbolic, T_LONG, string_con);
|
||||
return ArgToken(str);
|
||||
}
|
||||
const char* string(ArgToken token) {
|
||||
return (const char*) (intptr_t) token.get_jlong();
|
||||
return token.str();
|
||||
}
|
||||
void start_params() {
|
||||
_param_state <<= 1;
|
||||
|
||||
@ -126,26 +126,34 @@ public:
|
||||
Handle _handle;
|
||||
|
||||
public:
|
||||
ArgToken(TokenType tt = tt_illegal) : _tt(tt) {}
|
||||
ArgToken(TokenType tt, BasicType bt, jvalue value) : _tt(tt), _bt(bt), _value(value) {}
|
||||
ArgToken(TokenType tt = tt_illegal) : _tt(tt) {
|
||||
assert(tt == tt_illegal || tt == tt_void, "invalid token type");
|
||||
}
|
||||
|
||||
ArgToken(TokenType tt, BasicType bt, int index) : _tt(tt), _bt(bt) {
|
||||
assert(_tt == tt_parameter || _tt == tt_temporary, "must have index");
|
||||
_value.i = index;
|
||||
}
|
||||
|
||||
ArgToken(TokenType tt, BasicType bt, Handle value) : _tt(tt), _bt(bt) {
|
||||
_handle = value;
|
||||
ArgToken(BasicType bt, jvalue value) : _tt(tt_constant), _bt(bt), _value(value) {}
|
||||
ArgToken(BasicType bt, Handle value) : _tt(tt_constant), _bt(bt), _handle(value) {}
|
||||
|
||||
|
||||
ArgToken(const char* str) : _tt(tt_symbolic), _bt(T_LONG) {
|
||||
_value.j = (intptr_t)str;
|
||||
}
|
||||
|
||||
TokenType token_type() const { return _tt; }
|
||||
BasicType basic_type() const { return _bt; }
|
||||
int index() const { return _value.i; }
|
||||
Handle object() const { return _handle; }
|
||||
bool has_index() const { return _tt == tt_parameter || _tt == tt_temporary; }
|
||||
int index() const { assert(has_index(), "must have index");; return _value.i; }
|
||||
Handle object() const { assert(_tt == tt_constant, "value type"); return _handle; }
|
||||
const char* str() const { assert(_tt == tt_symbolic, "string type"); return (const char*)_value.j; }
|
||||
|
||||
jint get_jint() const { return _value.i; }
|
||||
jlong get_jlong() const { return _value.j; }
|
||||
jfloat get_jfloat() const { return _value.f; }
|
||||
jdouble get_jdouble() const { return _value.d; }
|
||||
jint get_jint() const { assert(_tt == tt_constant, "value types"); return _value.i; }
|
||||
jlong get_jlong() const { assert(_tt == tt_constant, "value types"); return _value.j; }
|
||||
jfloat get_jfloat() const { assert(_tt == tt_constant, "value types"); return _value.f; }
|
||||
jdouble get_jdouble() const { assert(_tt == tt_constant, "value types"); return _value.d; }
|
||||
};
|
||||
|
||||
// Abstract interpretation state:
|
||||
@ -256,7 +264,6 @@ public:
|
||||
// The IR happens to be JVM bytecodes.
|
||||
class MethodHandleCompiler : public MethodHandleWalker {
|
||||
private:
|
||||
methodHandle _callee;
|
||||
int _invoke_count; // count the original call site has been executed
|
||||
KlassHandle _rklass; // Return type for casting.
|
||||
BasicType _rtype;
|
||||
@ -404,7 +411,7 @@ private:
|
||||
return cpool_oop_reference_put(JVM_CONSTANT_NameAndType, name_index, signature_index);
|
||||
}
|
||||
|
||||
void emit_bc(Bytecodes::Code op, int index = 0);
|
||||
void emit_bc(Bytecodes::Code op, int index = 0, int args_size = -1);
|
||||
void emit_load(BasicType bt, int index);
|
||||
void emit_store(BasicType bt, int index);
|
||||
void emit_load_constant(ArgToken arg);
|
||||
@ -414,10 +421,10 @@ private:
|
||||
}
|
||||
virtual ArgToken make_oop_constant(oop con, TRAPS) {
|
||||
Handle h(THREAD, con);
|
||||
return ArgToken(tt_constant, T_OBJECT, h);
|
||||
return ArgToken(T_OBJECT, h);
|
||||
}
|
||||
virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) {
|
||||
return ArgToken(tt_constant, type, *con);
|
||||
return ArgToken(type, *con);
|
||||
}
|
||||
|
||||
virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS);
|
||||
@ -431,7 +438,7 @@ private:
|
||||
methodHandle get_method_oop(TRAPS) const;
|
||||
|
||||
public:
|
||||
MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
MethodHandleCompiler(Handle root, Symbol* name, Symbol* signature, int invoke_count, bool for_invokedynamic, TRAPS);
|
||||
|
||||
// Compile the given MH chain into bytecode.
|
||||
methodHandle compile(TRAPS);
|
||||
|
||||
@ -25,9 +25,11 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/oopMapCache.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/oopFactory.hpp"
|
||||
#include "prims/methodHandles.hpp"
|
||||
#include "prims/methodHandleWalk.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
#include "runtime/reflection.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
@ -2599,6 +2601,50 @@ void MethodHandles::ensure_vmlayout_field(Handle target, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
extern "C"
|
||||
void print_method_handle(oop mh);
|
||||
|
||||
static void stress_method_handle_walk_impl(Handle mh, TRAPS) {
|
||||
if (StressMethodHandleWalk) {
|
||||
// Exercise the MethodHandleWalk code in various ways and validate
|
||||
// the resulting method oop. Some of these produce output so they
|
||||
// are guarded under Verbose.
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
if (Verbose) {
|
||||
print_method_handle(mh());
|
||||
}
|
||||
TempNewSymbol name = SymbolTable::new_symbol("invoke", CHECK);
|
||||
Handle mt = java_lang_invoke_MethodHandle::type(mh());
|
||||
TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(mt(), true, CHECK);
|
||||
MethodHandleCompiler mhc(mh, name, signature, 10000, false, CHECK);
|
||||
methodHandle m = mhc.compile(CHECK);
|
||||
if (Verbose) {
|
||||
m->print_codes();
|
||||
}
|
||||
InterpreterOopMap mask;
|
||||
OopMapCache::compute_one_oop_map(m, m->code_size() - 1, &mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void stress_method_handle_walk(Handle mh, TRAPS) {
|
||||
stress_method_handle_walk_impl(mh, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop ex = PENDING_EXCEPTION;
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
tty->print("StressMethodHandleWalk: ");
|
||||
java_lang_Throwable::print(ex, tty);
|
||||
tty->cr();
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
static void stress_method_handle_walk(Handle mh, TRAPS) {}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Here are the native methods on sun.invoke.MethodHandleImpl.
|
||||
// They are the private interface between this JVM and the HotSpot-specific
|
||||
@ -2666,6 +2712,7 @@ JVM_ENTRY(void, MHN_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh,
|
||||
}
|
||||
|
||||
MethodHandles::init_DirectMethodHandle(mh, m, (do_dispatch != JNI_FALSE), CHECK);
|
||||
stress_method_handle_walk(mh, CHECK);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -2694,11 +2741,11 @@ JVM_ENTRY(void, MHN_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh,
|
||||
receiver_limit,
|
||||
decode_flags,
|
||||
CHECK);
|
||||
return;
|
||||
} else {
|
||||
// Build a BMH on top of a DMH or another BMH:
|
||||
MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
|
||||
}
|
||||
|
||||
// Build a BMH on top of a DMH or another BMH:
|
||||
MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
|
||||
stress_method_handle_walk(mh, CHECK);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -2716,6 +2763,7 @@ JVM_ENTRY(void, MHN_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh,
|
||||
assert(java_lang_invoke_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
|
||||
|
||||
MethodHandles::init_AdapterMethodHandle(mh, target, argnum, CHECK);
|
||||
stress_method_handle_walk(mh, CHECK);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
@ -2922,6 +2970,20 @@ JVM_ENTRY(jint, MHN_getMembers(JNIEnv *env, jobject igcls,
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jobject, MH_invoke_UOE(JNIEnv *env, jobject igmh, jobjectArray igargs)) {
|
||||
TempNewSymbol UOE_name = SymbolTable::new_symbol("java/lang/UnsupportedOperationException", CHECK_NULL);
|
||||
THROW_MSG_NULL(UOE_name, "MethodHandle.invoke cannot be invoked reflectively");
|
||||
return NULL;
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jobject, MH_invokeExact_UOE(JNIEnv *env, jobject igmh, jobjectArray igargs)) {
|
||||
TempNewSymbol UOE_name = SymbolTable::new_symbol("java/lang/UnsupportedOperationException", CHECK_NULL);
|
||||
THROW_MSG_NULL(UOE_name, "MethodHandle.invokeExact cannot be invoked reflectively");
|
||||
return NULL;
|
||||
}
|
||||
JVM_END
|
||||
|
||||
|
||||
/// JVM_RegisterMethodHandleMethods
|
||||
|
||||
@ -2960,6 +3022,12 @@ static JNINativeMethod methods[] = {
|
||||
{CC"getMembers", CC"("CLS""STRG""STRG"I"CLS"I["MEM")I", FN_PTR(MHN_getMembers)}
|
||||
};
|
||||
|
||||
static JNINativeMethod invoke_methods[] = {
|
||||
// void init(MemberName self, AccessibleObject ref)
|
||||
{CC"invoke", CC"(["OBJ")"OBJ, FN_PTR(MH_invoke_UOE)},
|
||||
{CC"invokeExact", CC"(["OBJ")"OBJ, FN_PTR(MH_invokeExact_UOE)}
|
||||
};
|
||||
|
||||
// This one function is exported, used by NativeLookup.
|
||||
|
||||
JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
|
||||
@ -2976,6 +3044,12 @@ JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class))
|
||||
ThreadToNativeFromVM ttnfv(thread);
|
||||
|
||||
int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod));
|
||||
if (!env->ExceptionOccurred()) {
|
||||
const char* L_MH_name = (JLINV "MethodHandle");
|
||||
const char* MH_name = L_MH_name+1;
|
||||
jclass MH_class = env->FindClass(MH_name);
|
||||
status = env->RegisterNatives(MH_class, invoke_methods, sizeof(invoke_methods)/sizeof(JNINativeMethod));
|
||||
}
|
||||
if (env->ExceptionOccurred()) {
|
||||
MethodHandles::set_enabled(false);
|
||||
warning("JSR 292 method handle code is mismatched to this JVM. Disabling support.");
|
||||
|
||||
@ -721,12 +721,10 @@ public:
|
||||
//# include "methodHandles_zero.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_arm
|
||||
#define TARGET_ARCH_NYI_6939861 1 //FIXME
|
||||
//# include "methodHandles_arm.hpp"
|
||||
# include "methodHandles_arm.hpp"
|
||||
#endif
|
||||
#ifdef TARGET_ARCH_ppc
|
||||
#define TARGET_ARCH_NYI_6939861 1 //FIXME
|
||||
//# include "methodHandles_ppc.hpp"
|
||||
# include "methodHandles_ppc.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef TARGET_ARCH_NYI_6939861
|
||||
|
||||
@ -2909,6 +2909,12 @@ class CommandLineFlags {
|
||||
product(intx, NmethodSweepCheckInterval, 5, \
|
||||
"Compilers wake up every n seconds to possibly sweep nmethods") \
|
||||
\
|
||||
notproduct(bool, LogSweeper, false, \
|
||||
"Keep a ring buffer of sweeper activity") \
|
||||
\
|
||||
notproduct(intx, SweeperLogEntries, 1024, \
|
||||
"Number of records in the ring buffer of sweeper activity") \
|
||||
\
|
||||
notproduct(intx, MemProfilingInterval, 500, \
|
||||
"Time between each invocation of the MemProfiler") \
|
||||
\
|
||||
@ -3718,6 +3724,9 @@ class CommandLineFlags {
|
||||
diagnostic(bool, OptimizeMethodHandles, true, \
|
||||
"when constructing method handles, try to improve them") \
|
||||
\
|
||||
develop(bool, StressMethodHandleWalk, false, \
|
||||
"Process all method handles with MethodHandleWalk") \
|
||||
\
|
||||
diagnostic(bool, UseRicochetFrames, true, \
|
||||
"use ricochet stack frames for method handle combination, " \
|
||||
"if the platform supports them") \
|
||||
|
||||
@ -37,6 +37,94 @@
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
#define SWEEP(nm) record_sweep(nm, __LINE__)
|
||||
// Sweeper logging code
|
||||
class SweeperRecord {
|
||||
public:
|
||||
int traversal;
|
||||
int invocation;
|
||||
int compile_id;
|
||||
long traversal_mark;
|
||||
int state;
|
||||
const char* kind;
|
||||
address vep;
|
||||
address uep;
|
||||
int line;
|
||||
|
||||
void print() {
|
||||
tty->print_cr("traversal = %d invocation = %d compile_id = %d %s uep = " PTR_FORMAT " vep = "
|
||||
PTR_FORMAT " state = %d traversal_mark %d line = %d",
|
||||
traversal,
|
||||
invocation,
|
||||
compile_id,
|
||||
kind == NULL ? "" : kind,
|
||||
uep,
|
||||
vep,
|
||||
state,
|
||||
traversal_mark,
|
||||
line);
|
||||
}
|
||||
};
|
||||
|
||||
static int _sweep_index = 0;
|
||||
static SweeperRecord* _records = NULL;
|
||||
|
||||
void NMethodSweeper::report_events(int id, address entry) {
|
||||
if (_records != NULL) {
|
||||
for (int i = _sweep_index; i < SweeperLogEntries; i++) {
|
||||
if (_records[i].uep == entry ||
|
||||
_records[i].vep == entry ||
|
||||
_records[i].compile_id == id) {
|
||||
_records[i].print();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _sweep_index; i++) {
|
||||
if (_records[i].uep == entry ||
|
||||
_records[i].vep == entry ||
|
||||
_records[i].compile_id == id) {
|
||||
_records[i].print();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NMethodSweeper::report_events() {
|
||||
if (_records != NULL) {
|
||||
for (int i = _sweep_index; i < SweeperLogEntries; i++) {
|
||||
// skip empty records
|
||||
if (_records[i].vep == NULL) continue;
|
||||
_records[i].print();
|
||||
}
|
||||
for (int i = 0; i < _sweep_index; i++) {
|
||||
// skip empty records
|
||||
if (_records[i].vep == NULL) continue;
|
||||
_records[i].print();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NMethodSweeper::record_sweep(nmethod* nm, int line) {
|
||||
if (_records != NULL) {
|
||||
_records[_sweep_index].traversal = _traversals;
|
||||
_records[_sweep_index].traversal_mark = nm->_stack_traversal_mark;
|
||||
_records[_sweep_index].invocation = _invocations;
|
||||
_records[_sweep_index].compile_id = nm->compile_id();
|
||||
_records[_sweep_index].kind = nm->compile_kind();
|
||||
_records[_sweep_index].state = nm->_state;
|
||||
_records[_sweep_index].vep = nm->verified_entry_point();
|
||||
_records[_sweep_index].uep = nm->entry_point();
|
||||
_records[_sweep_index].line = line;
|
||||
|
||||
_sweep_index = (_sweep_index + 1) % SweeperLogEntries;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define SWEEP(nm)
|
||||
#endif
|
||||
|
||||
|
||||
long NMethodSweeper::_traversals = 0; // No. of stack traversals performed
|
||||
nmethod* NMethodSweeper::_current = NULL; // Current nmethod
|
||||
int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache
|
||||
@ -137,6 +225,13 @@ void NMethodSweeper::possibly_sweep() {
|
||||
if (old != 0) {
|
||||
return;
|
||||
}
|
||||
#ifdef ASSERT
|
||||
if (LogSweeper && _records == NULL) {
|
||||
// Create the ring buffer for the logging code
|
||||
_records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries);
|
||||
memset(_records, 0, sizeof(SweeperRecord) * SweeperLogEntries);
|
||||
}
|
||||
#endif
|
||||
if (_invocations > 0) {
|
||||
sweep_code_cache();
|
||||
_invocations--;
|
||||
@ -213,10 +308,29 @@ void NMethodSweeper::sweep_code_cache() {
|
||||
}
|
||||
}
|
||||
|
||||
class NMethodMarker: public StackObj {
|
||||
private:
|
||||
CompilerThread* _thread;
|
||||
public:
|
||||
NMethodMarker(nmethod* nm) {
|
||||
_thread = CompilerThread::current();
|
||||
_thread->set_scanned_nmethod(nm);
|
||||
}
|
||||
~NMethodMarker() {
|
||||
_thread->set_scanned_nmethod(NULL);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
assert(!CodeCache_lock->owned_by_self(), "just checking");
|
||||
|
||||
// Make sure this nmethod doesn't get unloaded during the scan,
|
||||
// since the locks acquired below might safepoint.
|
||||
NMethodMarker nmm(nm);
|
||||
|
||||
SWEEP(nm);
|
||||
|
||||
// Skip methods that are currently referenced by the VM
|
||||
if (nm->is_locked_by_vm()) {
|
||||
// But still remember to clean-up inline caches for alive nmethods
|
||||
@ -224,8 +338,10 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
// Clean-up all inline caches that points to zombie/non-reentrant methods
|
||||
MutexLocker cl(CompiledIC_lock);
|
||||
nm->cleanup_inline_caches();
|
||||
SWEEP(nm);
|
||||
} else {
|
||||
_locked_seen++;
|
||||
SWEEP(nm);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -247,6 +363,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
}
|
||||
nm->mark_for_reclamation();
|
||||
_rescan = true;
|
||||
SWEEP(nm);
|
||||
}
|
||||
} else if (nm->is_not_entrant()) {
|
||||
// If there is no current activations of this method on the
|
||||
@ -257,6 +374,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
}
|
||||
nm->make_zombie();
|
||||
_rescan = true;
|
||||
SWEEP(nm);
|
||||
} else {
|
||||
// Still alive, clean up its inline caches
|
||||
MutexLocker cl(CompiledIC_lock);
|
||||
@ -265,6 +383,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
// request a rescan. If this method stays on the stack for a
|
||||
// long time we don't want to keep rescanning the code cache.
|
||||
_not_entrant_seen_on_stack++;
|
||||
SWEEP(nm);
|
||||
}
|
||||
} else if (nm->is_unloaded()) {
|
||||
// Unloaded code, just make it a zombie
|
||||
@ -273,10 +392,12 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
if (nm->is_osr_method()) {
|
||||
// No inline caches will ever point to osr methods, so we can just remove it
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
SWEEP(nm);
|
||||
nm->flush();
|
||||
} else {
|
||||
nm->make_zombie();
|
||||
_rescan = true;
|
||||
SWEEP(nm);
|
||||
}
|
||||
} else {
|
||||
assert(nm->is_alive(), "should be alive");
|
||||
@ -293,6 +414,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
|
||||
// Clean-up all inline caches that points to zombie/non-reentrant methods
|
||||
MutexLocker cl(CompiledIC_lock);
|
||||
nm->cleanup_inline_caches();
|
||||
SWEEP(nm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -57,6 +57,13 @@ class NMethodSweeper : public AllStatic {
|
||||
public:
|
||||
static long traversal_count() { return _traversals; }
|
||||
|
||||
#ifdef ASSERT
|
||||
// Keep track of sweeper activity in the ring buffer
|
||||
static void record_sweep(nmethod* nm, int line);
|
||||
static void report_events(int id, address entry);
|
||||
static void report_events();
|
||||
#endif
|
||||
|
||||
static void scan_stacks(); // Invoked at the end of each safepoint
|
||||
static void sweep_code_cache(); // Concurrent part of sweep job
|
||||
static void possibly_sweep(); // Compiler threads call this to sweep
|
||||
|
||||
@ -2861,6 +2861,7 @@ void JavaThread::trace_frames() {
|
||||
}
|
||||
|
||||
|
||||
#ifdef ASSERT
|
||||
// Print or validate the layout of stack frames
|
||||
void JavaThread::print_frame_layout(int depth, bool validate_only) {
|
||||
ResourceMark rm;
|
||||
@ -2878,7 +2879,7 @@ void JavaThread::print_frame_layout(int depth, bool validate_only) {
|
||||
values.print();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void JavaThread::trace_stack_from(vframe* start_vf) {
|
||||
ResourceMark rm;
|
||||
@ -2942,12 +2943,22 @@ CompilerThread::CompilerThread(CompileQueue* queue, CompilerCounters* counters)
|
||||
_queue = queue;
|
||||
_counters = counters;
|
||||
_buffer_blob = NULL;
|
||||
_scanned_nmethod = NULL;
|
||||
|
||||
#ifndef PRODUCT
|
||||
_ideal_graph_printer = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CompilerThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
||||
JavaThread::oops_do(f, cf);
|
||||
if (_scanned_nmethod != NULL && cf != NULL) {
|
||||
// Safepoints can occur when the sweeper is scanning an nmethod so
|
||||
// process it here to make sure it isn't unloaded in the middle of
|
||||
// a scan.
|
||||
cf->do_code_blob(_scanned_nmethod);
|
||||
}
|
||||
}
|
||||
|
||||
// ======= Threads ========
|
||||
|
||||
|
||||
@ -439,7 +439,7 @@ class Thread: public ThreadShadow {
|
||||
// GC support
|
||||
// Apply "f->do_oop" to all root oops in "this".
|
||||
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
|
||||
void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
virtual void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
|
||||
// Handles the parallel case for the method below.
|
||||
private:
|
||||
@ -1381,7 +1381,7 @@ public:
|
||||
void trace_frames() PRODUCT_RETURN;
|
||||
|
||||
// Print an annotated view of the stack frames
|
||||
void print_frame_layout(int depth = 0, bool validate_only = false) PRODUCT_RETURN;
|
||||
void print_frame_layout(int depth = 0, bool validate_only = false) NOT_DEBUG_RETURN;
|
||||
void validate_frame_layout() {
|
||||
print_frame_layout(0, true);
|
||||
}
|
||||
@ -1698,6 +1698,8 @@ class CompilerThread : public JavaThread {
|
||||
CompileQueue* _queue;
|
||||
BufferBlob* _buffer_blob;
|
||||
|
||||
nmethod* _scanned_nmethod; // nmethod being scanned by the sweeper
|
||||
|
||||
public:
|
||||
|
||||
static CompilerThread* current();
|
||||
@ -1726,6 +1728,11 @@ class CompilerThread : public JavaThread {
|
||||
_log = log;
|
||||
}
|
||||
|
||||
// GC support
|
||||
// Apply "f->do_oop" to all root oops in "this".
|
||||
// Apply "cf->do_code_blob" (if !NULL) to all code blobs active in frames
|
||||
void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||||
|
||||
#ifndef PRODUCT
|
||||
private:
|
||||
IdealGraphPrinter *_ideal_graph_printer;
|
||||
@ -1737,6 +1744,12 @@ public:
|
||||
// Get/set the thread's current task
|
||||
CompileTask* task() { return _task; }
|
||||
void set_task(CompileTask* task) { _task = task; }
|
||||
|
||||
// Track the nmethod currently being scanned by the sweeper
|
||||
void set_scanned_nmethod(nmethod* nm) {
|
||||
assert(_scanned_nmethod == NULL || nm == NULL, "should reset to NULL before writing a new value");
|
||||
_scanned_nmethod = nm;
|
||||
}
|
||||
};
|
||||
|
||||
inline CompilerThread* CompilerThread::current() {
|
||||
|
||||
@ -783,6 +783,7 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
nonstatic_field(nmethod, _osr_link, nmethod*) \
|
||||
nonstatic_field(nmethod, _scavenge_root_link, nmethod*) \
|
||||
nonstatic_field(nmethod, _scavenge_root_state, jbyte) \
|
||||
nonstatic_field(nmethod, _state, unsigned char) \
|
||||
nonstatic_field(nmethod, _exception_offset, int) \
|
||||
nonstatic_field(nmethod, _deoptimize_offset, int) \
|
||||
nonstatic_field(nmethod, _orig_pc_offset, int) \
|
||||
@ -800,6 +801,8 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
nonstatic_field(nmethod, _osr_entry_point, address) \
|
||||
nonstatic_field(nmethod, _lock_count, jint) \
|
||||
nonstatic_field(nmethod, _stack_traversal_mark, long) \
|
||||
nonstatic_field(nmethod, _compile_id, int) \
|
||||
nonstatic_field(nmethod, _marked_for_deoptimization, bool) \
|
||||
\
|
||||
/********************************/ \
|
||||
/* JavaCalls (NOTE: incomplete) */ \
|
||||
@ -1310,11 +1313,13 @@ static inline uint64_t cast_uint64_t(size_t x)
|
||||
\
|
||||
declare_toplevel_type(CodeBlob) \
|
||||
declare_type(BufferBlob, CodeBlob) \
|
||||
declare_type(nmethod, CodeBlob) \
|
||||
declare_type(AdapterBlob, BufferBlob) \
|
||||
declare_type(nmethod, CodeBlob) \
|
||||
declare_type(RuntimeStub, CodeBlob) \
|
||||
declare_type(SingletonBlob, CodeBlob) \
|
||||
declare_type(SafepointBlob, SingletonBlob) \
|
||||
declare_type(DeoptimizationBlob, SingletonBlob) \
|
||||
declare_type(RicochetBlob, SingletonBlob) \
|
||||
declare_c2_type(ExceptionBlob, SingletonBlob) \
|
||||
declare_c2_type(UncommonTrapBlob, CodeBlob) \
|
||||
\
|
||||
|
||||
@ -52,7 +52,7 @@ cp ${TESTSRC}/Test6890943.sh .
|
||||
|
||||
${TESTJAVA}/bin/javac -d . Test6890943.java
|
||||
|
||||
${TESTJAVA}/bin/java ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1
|
||||
${TESTJAVA}/bin/java -XX:-PrintVMOptions ${TESTVMOPTS} Test6890943 < input6890943.txt > test.out 2>&1
|
||||
|
||||
diff output6890943.txt test.out
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
* @bug 7005594
|
||||
* @summary Array overflow not handled correctly with loop optimzations
|
||||
*
|
||||
* @run main/othervm -Xms2048m -Xcomp -XX:CompileOnly=Test7005594.test Test7005594
|
||||
* @run shell Test7005594.sh
|
||||
*/
|
||||
|
||||
public class Test7005594 {
|
||||
|
||||
80
hotspot/test/compiler/5091921/Test7005594.sh
Normal file
80
hotspot/test/compiler/5091921/Test7005594.sh
Normal file
@ -0,0 +1,80 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2011, 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.
|
||||
#
|
||||
#
|
||||
|
||||
if [ "${TESTSRC}" = "" ]
|
||||
then
|
||||
echo "TESTSRC not set. Test cannot execute. Failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "TESTSRC=${TESTSRC}"
|
||||
if [ "${TESTJAVA}" = "" ]
|
||||
then
|
||||
echo "TESTJAVA not set. Test cannot execute. Failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "TESTJAVA=${TESTJAVA}"
|
||||
if [ "${TESTCLASSES}" = "" ]
|
||||
then
|
||||
echo "TESTCLASSES not set. Test cannot execute. Failed."
|
||||
exit 1
|
||||
fi
|
||||
echo "TESTCLASSES=${TESTCLASSES}"
|
||||
echo "CLASSPATH=${CLASSPATH}"
|
||||
|
||||
set -x
|
||||
|
||||
cp ${TESTSRC}/Test7005594.java .
|
||||
cp ${TESTSRC}/Test7005594.sh .
|
||||
|
||||
${TESTJAVA}/bin/javac -d . Test7005594.java
|
||||
|
||||
${TESTJAVA}/bin/java ${TESTVMOPTS} -Xms1600m -Xcomp -XX:CompileOnly=Test7005594.test Test7005594 > test.out 2>&1
|
||||
|
||||
result=$?
|
||||
|
||||
cat test.out
|
||||
|
||||
if [ $result -eq 95 ]
|
||||
then
|
||||
echo "Passed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ $result -eq 97 ]
|
||||
then
|
||||
echo "Failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The test should pass when no enough space for object heap
|
||||
grep "Could not reserve enough space for object heap" test.out
|
||||
if [ $? = 0 ]
|
||||
then
|
||||
echo "Passed"
|
||||
exit 0
|
||||
else
|
||||
echo "Failed"
|
||||
exit 1
|
||||
fi
|
||||
Loading…
x
Reference in New Issue
Block a user