Merge
This commit is contained in:
commit
9aa48d7d95
@ -53,3 +53,4 @@ d1516b9f23954b29b8e76e6f4efc467c08c78133 jdk7-b75
|
||||
c8b63075403d53a208104a8a6ea5072c1cb66aab jdk7-b76
|
||||
1f17ca8353babb13f4908c1f87d11508232518c8 jdk7-b77
|
||||
ab4ae8f4514693a9fe17ca2fec0239d8f8450d2c jdk7-b78
|
||||
20aeeb51713990dbea6929a2e100a8bbf5df70d4 jdk7-b79
|
||||
|
@ -53,3 +53,4 @@ b751c528c55560cf2adeaeef24b39ca1f4d1cbf7 jdk7-b73
|
||||
937144222e2219939101b0129d26a872a7956b13 jdk7-b76
|
||||
6881f0383f623394b5ec73f27a5f329ff55d0467 jdk7-b77
|
||||
a7f7276b48cd74d8eb1baa83fbf3d1ef4a2603c8 jdk7-b78
|
||||
ec0421b5703b677e2226cf4bf7ae4eaafd8061c5 jdk7-b79
|
||||
|
@ -123,7 +123,7 @@ public abstract class Expression
|
||||
|
||||
/**
|
||||
* Coerces a number to the target type of this expression.
|
||||
* @parm number The number to coerce.
|
||||
* @param obj The number to coerce.
|
||||
* @return the value of number coerced to the (target) type of
|
||||
* this expression.
|
||||
**/
|
||||
@ -142,7 +142,7 @@ public abstract class Expression
|
||||
/**
|
||||
* Coerces an integral value (BigInteger) to its corresponding unsigned
|
||||
* representation, if the target type of this expression is unsigned.
|
||||
* @parm b The BigInteger to be coerced.
|
||||
* @param b The BigInteger to be coerced.
|
||||
* @return the value of an integral type coerced to its corresponding
|
||||
* unsigned integral type, if the target type of this expression is
|
||||
* unsigned.
|
||||
@ -170,7 +170,7 @@ public abstract class Expression
|
||||
/**
|
||||
* Coerces an integral value (BigInteger) to its corresponding signed
|
||||
* representation, if the target type of this expression is signed.
|
||||
* @parm b The BigInteger to be coerced.
|
||||
* @param b The BigInteger to be coerced.
|
||||
* @return the value of an integral type coerced to its corresponding
|
||||
* signed integral type, if the target type of this expression is
|
||||
* signed.
|
||||
|
@ -161,7 +161,7 @@ public class PortableRemoteObject {
|
||||
* happens implicitly when the object is sent or received as an argument
|
||||
* on a remote method call, but in some circumstances it is useful to
|
||||
* perform this action by making an explicit call. See the
|
||||
* {@link Stub#connect} method for more information.
|
||||
* {@link javax.rmi.CORBA.Stub#connect} method for more information.
|
||||
* @param target the object to connect.
|
||||
* @param source a previously connected object.
|
||||
* @throws RemoteException if <code>source</code> is not connected
|
||||
|
@ -31,7 +31,7 @@ package org.omg.CORBA;
|
||||
* indicate whether policies should replace the
|
||||
* existing policies of an <code>Object</code> or be added to them.
|
||||
* <P>
|
||||
* The method {@link omg.org.CORBA.Object._set_policy_override} takes
|
||||
* The method {@link org.omg.CORBA.Object#_set_policy_override} takes
|
||||
* either <code>SetOverrideType.SET_OVERRIDE</code> or
|
||||
* <code>SetOverrideType.ADD_OVERRIDE</code> as its second argument.
|
||||
* The method <code>_set_policy_override</code>
|
||||
|
@ -545,8 +545,6 @@ public class TCKind {
|
||||
* @param _value the <code>int</code> to convert. It must be one of
|
||||
* the <code>int</code> constants in the class
|
||||
* <code>TCKind</code>.
|
||||
* @return a new <code>TCKind</code> instance whose <code>value</code>
|
||||
* field matches the given <code>int</code>
|
||||
*/
|
||||
@Deprecated
|
||||
protected TCKind(int _value){
|
||||
|
@ -56,7 +56,7 @@ public final class UnknownUserException extends UserException {
|
||||
* Constructs an <code>UnknownUserException</code> object that contains the given
|
||||
* <code>Any</code> object.
|
||||
*
|
||||
* @ param a an <code>Any</code> object that contains a user exception returned
|
||||
* @param a an <code>Any</code> object that contains a user exception returned
|
||||
* by the server
|
||||
*/
|
||||
public UnknownUserException(Any a) {
|
||||
|
@ -43,7 +43,6 @@ public class ServantObject
|
||||
/** The real servant. The local stub may cast this field to the expected type, and then
|
||||
* invoke the operation directly. Note, the object may or may not be the actual servant
|
||||
* instance.
|
||||
* @return The real servant
|
||||
*/
|
||||
public java.lang.Object servant;
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ module CosNaming
|
||||
*
|
||||
* @param n Name of the object <p>
|
||||
*
|
||||
* @parm obj The Object to rebind with the given name <p>
|
||||
* @param obj The Object to rebind with the given name <p>
|
||||
*
|
||||
* @exception org.omg.CosNaming.NamingContextPackage.NotFound Indicates the name does not identify a binding.<p>
|
||||
*
|
||||
|
@ -1730,7 +1730,7 @@ module PortableInterceptor {
|
||||
* <p>
|
||||
* Any number of components may exist with the same component ID.
|
||||
*
|
||||
* @param a_component The IOP.TaggedComponent to add.
|
||||
* @param tagged_component The IOP.TaggedComponent to add.
|
||||
*/
|
||||
void add_ior_component
|
||||
(in IOP::TaggedComponent tagged_component);
|
||||
@ -1744,7 +1744,7 @@ module PortableInterceptor {
|
||||
* <p>
|
||||
* Any number of components may exist with the same component ID.
|
||||
*
|
||||
* @param a_component The <code>IOP.TaggedComponent</code> to add.
|
||||
* @param tagged_component The <code>IOP.TaggedComponent</code> to add.
|
||||
* @param profile_id The profile id of the profile to
|
||||
* which this component will be added.
|
||||
* @exception BAD_PARAM thrown, with a standard minor code of 29, if the
|
||||
|
@ -53,3 +53,4 @@ d8dd291a362acb656026a9c0a9da48501505a1e7 jdk7-b75
|
||||
9174bb32e934965288121f75394874eeb1fcb649 jdk7-b76
|
||||
455105fc81d941482f8f8056afaa7aa0949c9300 jdk7-b77
|
||||
e703499b4b51e3af756ae77c3d5e8b3058a14e4e jdk7-b78
|
||||
a5a6adfca6ecefb5894a848debabfe442ff50e25 jdk7-b79
|
||||
|
@ -63,12 +63,12 @@ public class SystemDictionary {
|
||||
javaSystemLoaderField = type.getOopField("_java_system_loader");
|
||||
nofBuckets = db.lookupIntConstant("SystemDictionary::_nof_buckets").intValue();
|
||||
|
||||
objectKlassField = type.getOopField(WK_KLASS("object_klass"));
|
||||
classLoaderKlassField = type.getOopField(WK_KLASS("classloader_klass"));
|
||||
stringKlassField = type.getOopField(WK_KLASS("string_klass"));
|
||||
systemKlassField = type.getOopField(WK_KLASS("system_klass"));
|
||||
threadKlassField = type.getOopField(WK_KLASS("thread_klass"));
|
||||
threadGroupKlassField = type.getOopField(WK_KLASS("threadGroup_klass"));
|
||||
objectKlassField = type.getOopField(WK_KLASS("Object_klass"));
|
||||
classLoaderKlassField = type.getOopField(WK_KLASS("ClassLoader_klass"));
|
||||
stringKlassField = type.getOopField(WK_KLASS("String_klass"));
|
||||
systemKlassField = type.getOopField(WK_KLASS("System_klass"));
|
||||
threadKlassField = type.getOopField(WK_KLASS("Thread_klass"));
|
||||
threadGroupKlassField = type.getOopField(WK_KLASS("ThreadGroup_klass"));
|
||||
}
|
||||
|
||||
// This WK functions must follow the definitions in systemDictionary.hpp:
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2009
|
||||
|
||||
HS_MAJOR_VER=17
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=06
|
||||
HS_BUILD_NUMBER=07
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=7
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
// Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
@ -1885,6 +1885,10 @@ RegMask Matcher::modL_proj_mask() {
|
||||
return RegMask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
|
||||
return RegMask();
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
|
||||
@ -6664,7 +6668,7 @@ instruct cmovII_imm(cmpOp cmp, flagsReg icc, iRegI dst, immI11 src) %{
|
||||
ins_pipe(ialu_imm);
|
||||
%}
|
||||
|
||||
instruct cmovII_U_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{
|
||||
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);
|
||||
@ -6673,7 +6677,7 @@ instruct cmovII_U_reg(cmpOpU cmp, flagsRegU icc, iRegI dst, iRegI src) %{
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
instruct cmovII_U_imm(cmpOpU cmp, flagsRegU icc, iRegI dst, immI11 src) %{
|
||||
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);
|
||||
@ -6719,6 +6723,16 @@ instruct cmovNI_reg(cmpOp cmp, flagsReg icc, iRegN dst, iRegN src) %{
|
||||
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);
|
||||
@ -6756,6 +6770,16 @@ instruct cmovPI_reg(cmpOp cmp, flagsReg icc, iRegP dst, iRegP src) %{
|
||||
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);
|
||||
@ -6766,6 +6790,16 @@ instruct cmovPI_imm(cmpOp cmp, flagsReg icc, iRegP dst, immP0 src) %{
|
||||
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);
|
||||
@ -6805,6 +6839,17 @@ instruct cmovFI_reg(cmpOp cmp, flagsReg icc, regF dst, regF src) %{
|
||||
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)));
|
||||
@ -6838,6 +6883,17 @@ instruct cmovDI_reg(cmpOp cmp, flagsReg icc, regD dst, regD src) %{
|
||||
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)));
|
||||
@ -6877,6 +6933,17 @@ instruct cmovLI_reg(cmpOp cmp, flagsReg icc, iRegL dst, iRegL src) %{
|
||||
%}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -330,6 +330,14 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
|
||||
// This is the sp before any possible extension (adapter/locals).
|
||||
intptr_t* unextended_sp = interpreter_frame_sender_sp();
|
||||
|
||||
address sender_pc = this->sender_pc();
|
||||
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
|
||||
assert(sender_cb, "sanity");
|
||||
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
|
||||
if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
|
||||
unextended_sp = (intptr_t*) at(link_offset);
|
||||
}
|
||||
|
||||
// The interpreter and compiler(s) always save EBP/RBP in a known
|
||||
// location on entry. We must record where that location is
|
||||
// so this if EBP/RBP was live on callout from c2 we can find
|
||||
@ -352,7 +360,7 @@ frame frame::sender_for_interpreter_frame(RegisterMap* map) const {
|
||||
#endif // AMD64
|
||||
}
|
||||
#endif /* COMPILER2 */
|
||||
return frame(sp, unextended_sp, link(), sender_pc());
|
||||
return frame(sp, unextended_sp, link(), sender_pc);
|
||||
}
|
||||
|
||||
|
||||
@ -375,6 +383,18 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
|
||||
|
||||
intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset);
|
||||
|
||||
intptr_t* unextended_sp = sender_sp;
|
||||
// If we are returning to a compiled method handle call site,
|
||||
// the saved_fp will in fact be a saved value of the unextended SP.
|
||||
// The simplest way to tell whether we are returning to such a call
|
||||
// site is as follows:
|
||||
CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc);
|
||||
assert(sender_cb, "sanity");
|
||||
nmethod* sender_nm = sender_cb->as_nmethod_or_null();
|
||||
if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) {
|
||||
unextended_sp = saved_fp;
|
||||
}
|
||||
|
||||
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
|
||||
@ -399,7 +419,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const {
|
||||
}
|
||||
|
||||
assert(sender_sp != sp(), "must have changed");
|
||||
return frame(sender_sp, saved_fp, sender_pc);
|
||||
return frame(sender_sp, unextended_sp, saved_fp, sender_pc);
|
||||
}
|
||||
|
||||
frame frame::sender(RegisterMap* map) const {
|
||||
|
@ -225,11 +225,12 @@ inline methodOop* frame::interpreter_frame_method_addr() const {
|
||||
// top of expression stack
|
||||
inline intptr_t* frame::interpreter_frame_tos_address() const {
|
||||
intptr_t* last_sp = interpreter_frame_last_sp();
|
||||
if (last_sp == NULL ) {
|
||||
if (last_sp == NULL) {
|
||||
return sp();
|
||||
} else {
|
||||
// sp() may have been extended by an adapter
|
||||
assert(last_sp < fp() && last_sp >= sp(), "bad tos");
|
||||
// sp() may have been extended or shrunk by an adapter. At least
|
||||
// check that we don't fall behind the legal region.
|
||||
assert(last_sp < (intptr_t*) interpreter_frame_monitor_begin(), "bad tos");
|
||||
return last_sp;
|
||||
}
|
||||
}
|
||||
|
@ -65,9 +65,9 @@ static void verify_argslot(MacroAssembler* _masm, Register rax_argslot,
|
||||
// Verify that argslot lies within (rsp, rbp].
|
||||
Label L_ok, L_bad;
|
||||
__ cmpptr(rax_argslot, rbp);
|
||||
__ jcc(Assembler::above, L_bad);
|
||||
__ jccb(Assembler::above, L_bad);
|
||||
__ cmpptr(rsp, rax_argslot);
|
||||
__ jcc(Assembler::below, L_ok);
|
||||
__ jccb(Assembler::below, L_ok);
|
||||
__ bind(L_bad);
|
||||
__ stop(error_message);
|
||||
__ bind(L_ok);
|
||||
@ -136,9 +136,9 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
|
||||
if (arg_slots.is_register()) {
|
||||
Label L_ok, L_bad;
|
||||
__ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
|
||||
__ jcc(Assembler::greater, L_bad);
|
||||
__ jccb(Assembler::greater, L_bad);
|
||||
__ testl(arg_slots.as_register(), -stack_move_unit() - 1);
|
||||
__ jcc(Assembler::zero, L_ok);
|
||||
__ jccb(Assembler::zero, L_ok);
|
||||
__ bind(L_bad);
|
||||
__ stop("assert arg_slots <= 0 and clear low bits");
|
||||
__ bind(L_ok);
|
||||
@ -173,7 +173,7 @@ void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
|
||||
__ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
|
||||
__ addptr(rdx_temp, wordSize);
|
||||
__ cmpptr(rdx_temp, rax_argslot);
|
||||
__ jcc(Assembler::less, loop);
|
||||
__ jccb(Assembler::less, loop);
|
||||
}
|
||||
|
||||
// Now move the argslot down, to point to the opened-up space.
|
||||
@ -211,9 +211,9 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
||||
Label L_ok, L_bad;
|
||||
__ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr));
|
||||
__ cmpptr(rbx_temp, rbp);
|
||||
__ jcc(Assembler::above, L_bad);
|
||||
__ jccb(Assembler::above, L_bad);
|
||||
__ cmpptr(rsp, rax_argslot);
|
||||
__ jcc(Assembler::below, L_ok);
|
||||
__ jccb(Assembler::below, L_ok);
|
||||
__ bind(L_bad);
|
||||
__ stop("deleted argument(s) must fall within current frame");
|
||||
__ bind(L_ok);
|
||||
@ -221,9 +221,9 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
||||
if (arg_slots.is_register()) {
|
||||
Label L_ok, L_bad;
|
||||
__ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
|
||||
__ jcc(Assembler::less, L_bad);
|
||||
__ jccb(Assembler::less, L_bad);
|
||||
__ testl(arg_slots.as_register(), -stack_move_unit() - 1);
|
||||
__ jcc(Assembler::zero, L_ok);
|
||||
__ jccb(Assembler::zero, L_ok);
|
||||
__ bind(L_bad);
|
||||
__ stop("assert arg_slots >= 0 and clear low bits");
|
||||
__ bind(L_ok);
|
||||
@ -258,7 +258,7 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
||||
__ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
|
||||
__ addptr(rdx_temp, -wordSize);
|
||||
__ cmpptr(rdx_temp, rsp);
|
||||
__ jcc(Assembler::greaterEqual, loop);
|
||||
__ jccb(Assembler::greaterEqual, loop);
|
||||
}
|
||||
|
||||
// Now move the argslot up, to point to the just-copied block.
|
||||
@ -268,8 +268,9 @@ void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
extern "C" void print_method_handle(oop mh);
|
||||
void trace_method_handle_stub(const char* adaptername,
|
||||
oopDesc* mh,
|
||||
oop mh,
|
||||
intptr_t* entry_sp,
|
||||
intptr_t* saved_sp,
|
||||
intptr_t* saved_bp) {
|
||||
@ -280,6 +281,7 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp);
|
||||
if (last_sp != saved_sp)
|
||||
printf("*** last_sp="INTPTR_FORMAT"\n", (intptr_t)last_sp);
|
||||
if (Verbose) print_method_handle(mh);
|
||||
}
|
||||
#endif //PRODUCT
|
||||
|
||||
@ -382,11 +384,11 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
// FIXME: fill in _raise_exception_method with a suitable sun.dyn method
|
||||
__ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method));
|
||||
__ testptr(rbx_method, rbx_method);
|
||||
__ jcc(Assembler::zero, no_method);
|
||||
__ jccb(Assembler::zero, no_method);
|
||||
int jobject_oop_offset = 0;
|
||||
__ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject
|
||||
__ testptr(rbx_method, rbx_method);
|
||||
__ jcc(Assembler::zero, no_method);
|
||||
__ jccb(Assembler::zero, no_method);
|
||||
__ verify_oop(rbx_method);
|
||||
__ push(rdi_pc); // and restore caller PC
|
||||
__ jmp(rbx_method_fie);
|
||||
@ -533,16 +535,15 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
if (arg_type == T_OBJECT) {
|
||||
__ movptr(Address(rax_argslot, 0), rbx_temp);
|
||||
} else {
|
||||
__ load_sized_value(rbx_temp, prim_value_addr,
|
||||
__ load_sized_value(rdx_temp, prim_value_addr,
|
||||
type2aelembytes(arg_type), is_signed_subword_type(arg_type));
|
||||
__ movptr(Address(rax_argslot, 0), rbx_temp);
|
||||
__ movptr(Address(rax_argslot, 0), rdx_temp);
|
||||
#ifndef _LP64
|
||||
if (arg_slots == 2) {
|
||||
__ movl(rbx_temp, prim_value_addr.plus_disp(wordSize));
|
||||
__ movl(Address(rax_argslot, Interpreter::stackElementSize()), rbx_temp);
|
||||
__ movl(rdx_temp, prim_value_addr.plus_disp(wordSize));
|
||||
__ movl(Address(rax_argslot, Interpreter::stackElementSize()), rdx_temp);
|
||||
}
|
||||
#endif //_LP64
|
||||
break;
|
||||
}
|
||||
|
||||
if (direct_to_method) {
|
||||
@ -584,7 +585,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
Label done;
|
||||
__ movptr(rdx_temp, vmarg);
|
||||
__ testl(rdx_temp, rdx_temp);
|
||||
__ jcc(Assembler::zero, done); // no cast if null
|
||||
__ jccb(Assembler::zero, done); // no cast if null
|
||||
__ load_klass(rdx_temp, rdx_temp);
|
||||
|
||||
// live at this point:
|
||||
@ -675,24 +676,24 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
// (now we are done with the old MH)
|
||||
|
||||
// original 32-bit vmdata word must be of this form:
|
||||
// | MBZ:16 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 |
|
||||
__ xchgl(rcx, rbx_vminfo); // free rcx for shifts
|
||||
// | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 |
|
||||
__ xchgptr(rcx, rbx_vminfo); // free rcx for shifts
|
||||
__ shll(rdx_temp /*, rcx*/);
|
||||
Label zero_extend, done;
|
||||
__ testl(rcx, CONV_VMINFO_SIGN_FLAG);
|
||||
__ jcc(Assembler::zero, zero_extend);
|
||||
__ jccb(Assembler::zero, zero_extend);
|
||||
|
||||
// this path is taken for int->byte, int->short
|
||||
__ sarl(rdx_temp /*, rcx*/);
|
||||
__ jmp(done);
|
||||
__ jmpb(done);
|
||||
|
||||
__ bind(zero_extend);
|
||||
// this is taken for int->char
|
||||
__ shrl(rdx_temp /*, rcx*/);
|
||||
|
||||
__ bind(done);
|
||||
__ movptr(vmarg, rdx_temp);
|
||||
__ xchgl(rcx, rbx_vminfo); // restore rcx_recv
|
||||
__ movl(vmarg, rdx_temp);
|
||||
__ xchgptr(rcx, rbx_vminfo); // restore rcx_recv
|
||||
|
||||
__ jump_to_method_handle_entry(rcx_recv, rdx_temp);
|
||||
}
|
||||
@ -861,7 +862,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
// Verify that argslot > destslot, by at least swap_bytes.
|
||||
Label L_ok;
|
||||
__ cmpptr(rax_argslot, rbx_destslot);
|
||||
__ jcc(Assembler::aboveEqual, L_ok);
|
||||
__ jccb(Assembler::aboveEqual, L_ok);
|
||||
__ stop("source must be above destination (upward rotation)");
|
||||
__ bind(L_ok);
|
||||
}
|
||||
@ -877,7 +878,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ movptr(Address(rax_argslot, swap_bytes), rdx_temp);
|
||||
__ addptr(rax_argslot, -wordSize);
|
||||
__ cmpptr(rax_argslot, rbx_destslot);
|
||||
__ jcc(Assembler::aboveEqual, loop);
|
||||
__ jccb(Assembler::aboveEqual, loop);
|
||||
} else {
|
||||
__ addptr(rax_argslot, swap_bytes);
|
||||
#ifdef ASSERT
|
||||
@ -885,7 +886,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
// Verify that argslot < destslot, by at least swap_bytes.
|
||||
Label L_ok;
|
||||
__ cmpptr(rax_argslot, rbx_destslot);
|
||||
__ jcc(Assembler::belowEqual, L_ok);
|
||||
__ jccb(Assembler::belowEqual, L_ok);
|
||||
__ stop("source must be below destination (downward rotation)");
|
||||
__ bind(L_ok);
|
||||
}
|
||||
@ -901,7 +902,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ movptr(Address(rax_argslot, -swap_bytes), rdx_temp);
|
||||
__ addptr(rax_argslot, wordSize);
|
||||
__ cmpptr(rax_argslot, rbx_destslot);
|
||||
__ jcc(Assembler::belowEqual, loop);
|
||||
__ jccb(Assembler::belowEqual, loop);
|
||||
}
|
||||
|
||||
// pop the original first chunk into the destination slot, now free
|
||||
@ -967,7 +968,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
__ addptr(rax_argslot, wordSize);
|
||||
__ addptr(rdx_newarg, wordSize);
|
||||
__ cmpptr(rdx_newarg, rbx_oldarg);
|
||||
__ jcc(Assembler::less, loop);
|
||||
__ jccb(Assembler::less, loop);
|
||||
|
||||
__ pop(rdi); // restore temp
|
||||
|
||||
@ -1119,7 +1120,7 @@ void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHan
|
||||
}
|
||||
__ addptr(rax_argslot, Interpreter::stackElementSize());
|
||||
__ cmpptr(rax_argslot, rdx_argslot_limit);
|
||||
__ jcc(Assembler::less, loop);
|
||||
__ jccb(Assembler::less, loop);
|
||||
} else if (length_constant == 0) {
|
||||
__ bind(skip_array_check);
|
||||
// nothing to copy
|
||||
|
@ -43,11 +43,11 @@ ExceptionBlob* OptoRuntime::_exception_blob;
|
||||
// This code is entered with a jmp.
|
||||
//
|
||||
// Arguments:
|
||||
// rax,: exception oop
|
||||
// rax: exception oop
|
||||
// rdx: exception pc
|
||||
//
|
||||
// Results:
|
||||
// rax,: exception oop
|
||||
// rax: exception oop
|
||||
// rdx: exception pc in caller or ???
|
||||
// destination: exception handler of caller
|
||||
//
|
||||
@ -113,17 +113,17 @@ void OptoRuntime::generate_exception_blob() {
|
||||
__ addptr(rsp, return_off * wordSize); // Epilog!
|
||||
__ pop(rdx); // Exception pc
|
||||
|
||||
// rax: exception handler for given <exception oop/exception pc>
|
||||
|
||||
// rax,: exception handler for given <exception oop/exception pc>
|
||||
// Restore SP from BP if the exception PC is a MethodHandle call.
|
||||
__ cmpl(Address(rcx, JavaThread::is_method_handle_exception_offset()), 0);
|
||||
__ cmovptr(Assembler::notEqual, rsp, rbp);
|
||||
|
||||
// We have a handler in rax, (could be deopt blob)
|
||||
// rdx - throwing pc, deopt blob will need it.
|
||||
|
||||
__ push(rax);
|
||||
|
||||
// rcx contains handler address
|
||||
|
||||
__ get_thread(rcx); // TLS
|
||||
// Get the exception
|
||||
__ movptr(rax, Address(rcx, JavaThread::exception_oop_offset()));
|
||||
// Get the exception pc in case we are deoptimized
|
||||
@ -137,7 +137,7 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
__ pop(rcx);
|
||||
|
||||
// rax,: exception oop
|
||||
// rax: exception oop
|
||||
// rcx: exception handler
|
||||
// rdx: exception pc
|
||||
__ jmp (rcx);
|
||||
|
@ -638,6 +638,10 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
|
||||
__ movptr(rax, Address(rsp, 0));
|
||||
|
||||
// Must preserve original SP for loading incoming arguments because
|
||||
// we need to align the outgoing SP for compiled code.
|
||||
__ movptr(r11, rsp);
|
||||
|
||||
// Cut-out for having no stack args. Since up to 2 int/oop args are passed
|
||||
// in registers, we will occasionally have no stack args.
|
||||
int comp_words_on_stack = 0;
|
||||
@ -661,6 +665,10 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
// as far as the placement of the call instruction
|
||||
__ push(rax);
|
||||
|
||||
// Put saved SP in another register
|
||||
const Register saved_sp = rax;
|
||||
__ movptr(saved_sp, r11);
|
||||
|
||||
// Will jump to the compiled code just as if compiled code was doing it.
|
||||
// Pre-load the register-jump target early, to schedule it better.
|
||||
__ movptr(r11, Address(rbx, in_bytes(methodOopDesc::from_compiled_offset())));
|
||||
@ -680,11 +688,7 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(),
|
||||
"scrambled load targets?");
|
||||
// Load in argument order going down.
|
||||
// int ld_off = (total_args_passed + comp_words_on_stack -i)*wordSize;
|
||||
// base ld_off on r13 (sender_sp) as the stack alignment makes offsets from rsp
|
||||
// unpredictable
|
||||
int ld_off = ((total_args_passed - 1) - i)*Interpreter::stackElementSize();
|
||||
|
||||
int ld_off = (total_args_passed - i)*Interpreter::stackElementSize() + Interpreter::value_offset_in_bytes();
|
||||
// Point to interpreter value (vs. tag)
|
||||
int next_off = ld_off - Interpreter::stackElementSize();
|
||||
//
|
||||
@ -699,10 +703,14 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
if (r_1->is_stack()) {
|
||||
// Convert stack slot to an SP offset (+ wordSize to account for return address )
|
||||
int st_off = regs[i].first()->reg2stack()*VMRegImpl::stack_slot_size + wordSize;
|
||||
|
||||
// We can use r13 as a temp here because compiled code doesn't need r13 as an input
|
||||
// and if we end up going thru a c2i because of a miss a reasonable value of r13
|
||||
// will be generated.
|
||||
if (!r_2->is_valid()) {
|
||||
// sign extend???
|
||||
__ movl(rax, Address(r13, ld_off));
|
||||
__ movptr(Address(rsp, st_off), rax);
|
||||
__ movl(r13, Address(saved_sp, ld_off));
|
||||
__ movptr(Address(rsp, st_off), r13);
|
||||
} else {
|
||||
//
|
||||
// We are using two optoregs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE
|
||||
@ -715,9 +723,9 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
// ld_off is MSW so get LSW
|
||||
const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
|
||||
next_off : ld_off;
|
||||
__ movq(rax, Address(r13, offset));
|
||||
__ movq(r13, Address(saved_sp, offset));
|
||||
// st_off is LSW (i.e. reg.first())
|
||||
__ movq(Address(rsp, st_off), rax);
|
||||
__ movq(Address(rsp, st_off), r13);
|
||||
}
|
||||
} else if (r_1->is_Register()) { // Register argument
|
||||
Register r = r_1->as_Register();
|
||||
@ -732,16 +740,16 @@ static void gen_i2c_adapter(MacroAssembler *masm,
|
||||
next_off : ld_off;
|
||||
|
||||
// this can be a misaligned move
|
||||
__ movq(r, Address(r13, offset));
|
||||
__ movq(r, Address(saved_sp, offset));
|
||||
} else {
|
||||
// sign extend and use a full word?
|
||||
__ movl(r, Address(r13, ld_off));
|
||||
__ movl(r, Address(saved_sp, ld_off));
|
||||
}
|
||||
} else {
|
||||
if (!r_2->is_valid()) {
|
||||
__ movflt(r_1->as_XMMRegister(), Address(r13, ld_off));
|
||||
__ movflt(r_1->as_XMMRegister(), Address(saved_sp, ld_off));
|
||||
} else {
|
||||
__ movdbl(r_1->as_XMMRegister(), Address(r13, next_off));
|
||||
__ movdbl(r_1->as_XMMRegister(), Address(saved_sp, next_off));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3319,6 +3327,10 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
// rax: exception handler
|
||||
|
||||
// Restore SP from BP if the exception PC is a MethodHandle call.
|
||||
__ cmpl(Address(r15_thread, JavaThread::is_method_handle_exception_offset()), 0);
|
||||
__ cmovptr(Assembler::notEqual, rsp, rbp);
|
||||
|
||||
// We have a handler in rax (could be deopt blob).
|
||||
__ mov(r8, rax);
|
||||
|
||||
|
@ -1488,7 +1488,10 @@ int AbstractInterpreter::layout_activation(methodOop method,
|
||||
|
||||
if (interpreter_frame != NULL) {
|
||||
#ifdef ASSERT
|
||||
assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
|
||||
if (!EnableMethodHandles)
|
||||
// @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences?
|
||||
// Probably, since deoptimization doesn't work yet.
|
||||
assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
|
||||
assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)");
|
||||
#endif
|
||||
|
||||
|
@ -449,8 +449,12 @@ void InterpreterGenerator::generate_stack_overflow_check(void) {
|
||||
__ addptr(rax, stack_base);
|
||||
__ subptr(rax, stack_size);
|
||||
|
||||
// Use the maximum number of pages we might bang.
|
||||
const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages :
|
||||
(StackRedPages+StackYellowPages);
|
||||
|
||||
// add in the red and yellow zone sizes
|
||||
__ addptr(rax, (StackRedPages + StackYellowPages) * page_size);
|
||||
__ addptr(rax, max_pages * page_size);
|
||||
|
||||
// check against the current stack bottom
|
||||
__ cmpptr(rsp, rax);
|
||||
@ -1502,8 +1506,10 @@ int AbstractInterpreter::layout_activation(methodOop method,
|
||||
tempcount* Interpreter::stackElementWords() + popframe_extra_args;
|
||||
if (interpreter_frame != NULL) {
|
||||
#ifdef ASSERT
|
||||
assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(),
|
||||
"Frame not properly walkable");
|
||||
if (!EnableMethodHandles)
|
||||
// @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences?
|
||||
// Probably, since deoptimization doesn't work yet.
|
||||
assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
|
||||
assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)");
|
||||
#endif
|
||||
|
||||
|
@ -268,22 +268,36 @@ static jlong *double_signmask_pool = double_quadword(&fp_signmask_pool[2*2], CON
|
||||
static jlong *float_signflip_pool = double_quadword(&fp_signmask_pool[3*2], CONST64(0x8000000080000000), CONST64(0x8000000080000000));
|
||||
static jlong *double_signflip_pool = double_quadword(&fp_signmask_pool[4*2], CONST64(0x8000000000000000), CONST64(0x8000000000000000));
|
||||
|
||||
// Offset hacking within calls.
|
||||
static int pre_call_FPU_size() {
|
||||
if (Compile::current()->in_24_bit_fp_mode())
|
||||
return 6; // fldcw
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int preserve_SP_size() {
|
||||
return LP64_ONLY(1 +) 2; // [rex,] op, rm(reg/reg)
|
||||
}
|
||||
|
||||
// !!!!! 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.
|
||||
int MachCallStaticJavaNode::ret_addr_offset() {
|
||||
return 5 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); // 5 bytes from start of call to where return address points
|
||||
int offset = 5 + pre_call_FPU_size(); // 5 bytes from start of call to where return address points
|
||||
if (_method_handle_invoke)
|
||||
offset += preserve_SP_size();
|
||||
return offset;
|
||||
}
|
||||
|
||||
int MachCallDynamicJavaNode::ret_addr_offset() {
|
||||
return 10 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0); // 10 bytes from start of call to where return address points
|
||||
return 10 + pre_call_FPU_size(); // 10 bytes from start of call to where return address points
|
||||
}
|
||||
|
||||
static int sizeof_FFree_Float_Stack_All = -1;
|
||||
|
||||
int MachCallRuntimeNode::ret_addr_offset() {
|
||||
assert(sizeof_FFree_Float_Stack_All != -1, "must have been emitted already");
|
||||
return sizeof_FFree_Float_Stack_All + 5 + (Compile::current()->in_24_bit_fp_mode() ? 6 : 0);
|
||||
return sizeof_FFree_Float_Stack_All + 5 + pre_call_FPU_size();
|
||||
}
|
||||
|
||||
// Indicate if the safepoint node needs the polling page as an input.
|
||||
@ -299,8 +313,16 @@ bool SafePointNode::needs_polling_address_input() {
|
||||
// The address of the call instruction needs to be 4-byte aligned to
|
||||
// ensure that it does not span a cache line so that it can be patched.
|
||||
int CallStaticJavaDirectNode::compute_padding(int current_offset) const {
|
||||
if (Compile::current()->in_24_bit_fp_mode())
|
||||
current_offset += 6; // skip fldcw in pre_call_FPU, if any
|
||||
current_offset += pre_call_FPU_size(); // skip fldcw, if any
|
||||
current_offset += 1; // skip call opcode byte
|
||||
return round_to(current_offset, alignment_required()) - current_offset;
|
||||
}
|
||||
|
||||
// The address of the call instruction needs to be 4-byte aligned to
|
||||
// ensure that it does not span a cache line so that it can be patched.
|
||||
int CallStaticJavaHandleNode::compute_padding(int current_offset) const {
|
||||
current_offset += pre_call_FPU_size(); // skip fldcw, if any
|
||||
current_offset += preserve_SP_size(); // skip mov rbp, rsp
|
||||
current_offset += 1; // skip call opcode byte
|
||||
return round_to(current_offset, alignment_required()) - current_offset;
|
||||
}
|
||||
@ -308,8 +330,7 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const {
|
||||
// The address of the call instruction needs to be 4-byte aligned to
|
||||
// ensure that it does not span a cache line so that it can be patched.
|
||||
int CallDynamicJavaDirectNode::compute_padding(int current_offset) const {
|
||||
if (Compile::current()->in_24_bit_fp_mode())
|
||||
current_offset += 6; // skip fldcw in pre_call_FPU, if any
|
||||
current_offset += pre_call_FPU_size(); // skip fldcw, if any
|
||||
current_offset += 5; // skip MOV instruction
|
||||
current_offset += 1; // skip call opcode byte
|
||||
return round_to(current_offset, alignment_required()) - current_offset;
|
||||
@ -1460,6 +1481,10 @@ RegMask Matcher::modL_proj_mask() {
|
||||
return RegMask();
|
||||
}
|
||||
|
||||
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
|
||||
return EBP_REG_mask;
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
//----------ENCODING BLOCK-----------------------------------------------------
|
||||
@ -1772,10 +1797,13 @@ encode %{
|
||||
|
||||
enc_class pre_call_FPU %{
|
||||
// If method sets FPU control word restore it here
|
||||
debug_only(int off0 = cbuf.code_size());
|
||||
if( Compile::current()->in_24_bit_fp_mode() ) {
|
||||
MacroAssembler masm(&cbuf);
|
||||
masm.fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_std()));
|
||||
}
|
||||
debug_only(int off1 = cbuf.code_size());
|
||||
assert(off1 - off0 == pre_call_FPU_size(), "correct size prediction");
|
||||
%}
|
||||
|
||||
enc_class post_call_FPU %{
|
||||
@ -1786,6 +1814,21 @@ encode %{
|
||||
}
|
||||
%}
|
||||
|
||||
enc_class preserve_SP %{
|
||||
debug_only(int off0 = cbuf.code_size());
|
||||
MacroAssembler _masm(&cbuf);
|
||||
// RBP is preserved across all calls, even compiled calls.
|
||||
// Use it to preserve RSP in places where the callee might change the SP.
|
||||
__ movptr(rbp, rsp);
|
||||
debug_only(int off1 = cbuf.code_size());
|
||||
assert(off1 - off0 == preserve_SP_size(), "correct size prediction");
|
||||
%}
|
||||
|
||||
enc_class restore_SP %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
__ movptr(rsp, rbp);
|
||||
%}
|
||||
|
||||
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.
|
||||
@ -13406,6 +13449,7 @@ instruct cmovXX_reg_LEGT(cmpOp_commute cmp, flagsReg_long_LEGT flags, regX dst,
|
||||
// compute_padding() functions will have to be adjusted.
|
||||
instruct CallStaticJavaDirect(method meth) %{
|
||||
match(CallStaticJava);
|
||||
predicate(! ((CallStaticJavaNode*)n)->is_method_handle_invoke());
|
||||
effect(USE meth);
|
||||
|
||||
ins_cost(300);
|
||||
@ -13420,6 +13464,30 @@ instruct CallStaticJavaDirect(method meth) %{
|
||||
ins_alignment(4);
|
||||
%}
|
||||
|
||||
// Call Java Static Instruction (method handle version)
|
||||
// Note: If this code changes, the corresponding ret_addr_offset() and
|
||||
// compute_padding() functions will have to be adjusted.
|
||||
instruct CallStaticJavaHandle(method meth, eBPRegP ebp) %{
|
||||
match(CallStaticJava);
|
||||
predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke());
|
||||
effect(USE meth);
|
||||
// EBP is saved by all callees (for interpreter stack correction).
|
||||
// We use it here for a similar purpose, in {preserve,restore}_SP.
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "CALL,static/MethodHandle " %}
|
||||
opcode(0xE8); /* E8 cd */
|
||||
ins_encode( pre_call_FPU,
|
||||
preserve_SP,
|
||||
Java_Static_Call( meth ),
|
||||
restore_SP,
|
||||
call_epilog,
|
||||
post_call_FPU );
|
||||
ins_pipe( pipe_slow );
|
||||
ins_pc_relative(1);
|
||||
ins_alignment(4);
|
||||
%}
|
||||
|
||||
// Call Java Dynamic Instruction
|
||||
// Note: If this code changes, the corresponding ret_addr_offset() and
|
||||
// compute_padding() functions will have to be adjusted.
|
||||
|
@ -551,12 +551,19 @@ source %{
|
||||
|
||||
#define __ _masm.
|
||||
|
||||
static int preserve_SP_size() {
|
||||
return LP64_ONLY(1 +) 2; // [rex,] op, rm(reg/reg)
|
||||
}
|
||||
|
||||
// !!!!! Special hack to get all types of calls to specify the byte offset
|
||||
// from the start of the call to the point where the return address
|
||||
// will point.
|
||||
int MachCallStaticJavaNode::ret_addr_offset()
|
||||
{
|
||||
return 5; // 5 bytes from start of call to where return address points
|
||||
int offset = 5; // 5 bytes from start of call to where return address points
|
||||
if (_method_handle_invoke)
|
||||
offset += preserve_SP_size();
|
||||
return offset;
|
||||
}
|
||||
|
||||
int MachCallDynamicJavaNode::ret_addr_offset()
|
||||
@ -587,6 +594,15 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const
|
||||
return round_to(current_offset, alignment_required()) - current_offset;
|
||||
}
|
||||
|
||||
// The address of the call instruction needs to be 4-byte aligned to
|
||||
// ensure that it does not span a cache line so that it can be patched.
|
||||
int CallStaticJavaHandleNode::compute_padding(int current_offset) const
|
||||
{
|
||||
current_offset += preserve_SP_size(); // skip mov rbp, rsp
|
||||
current_offset += 1; // skip call opcode byte
|
||||
return round_to(current_offset, alignment_required()) - current_offset;
|
||||
}
|
||||
|
||||
// The address of the call instruction needs to be 4-byte aligned to
|
||||
// ensure that it does not span a cache line so that it can be patched.
|
||||
int CallDynamicJavaDirectNode::compute_padding(int current_offset) const
|
||||
@ -2113,6 +2129,10 @@ RegMask Matcher::modL_proj_mask() {
|
||||
return LONG_RDX_REG_mask;
|
||||
}
|
||||
|
||||
const RegMask Matcher::method_handle_invoke_SP_save_mask() {
|
||||
return PTR_RBP_REG_mask;
|
||||
}
|
||||
|
||||
static Address build_address(int b, int i, int s, int d) {
|
||||
Register index = as_Register(i);
|
||||
Address::ScaleFactor scale = (Address::ScaleFactor)s;
|
||||
@ -2608,6 +2628,21 @@ encode %{
|
||||
RELOC_DISP32);
|
||||
%}
|
||||
|
||||
enc_class preserve_SP %{
|
||||
debug_only(int off0 = cbuf.code_size());
|
||||
MacroAssembler _masm(&cbuf);
|
||||
// RBP is preserved across all calls, even compiled calls.
|
||||
// Use it to preserve RSP in places where the callee might change the SP.
|
||||
__ movptr(rbp, rsp);
|
||||
debug_only(int off1 = cbuf.code_size());
|
||||
assert(off1 - off0 == preserve_SP_size(), "correct size prediction");
|
||||
%}
|
||||
|
||||
enc_class restore_SP %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
__ movptr(rsp, rbp);
|
||||
%}
|
||||
|
||||
enc_class Java_Static_Call(method meth)
|
||||
%{
|
||||
// JAVA STATIC CALL
|
||||
@ -12526,9 +12561,9 @@ instruct safePoint_poll(rFlagsReg cr)
|
||||
// Call Java Static Instruction
|
||||
// Note: If this code changes, the corresponding ret_addr_offset() and
|
||||
// compute_padding() functions will have to be adjusted.
|
||||
instruct CallStaticJavaDirect(method meth)
|
||||
%{
|
||||
instruct CallStaticJavaDirect(method meth) %{
|
||||
match(CallStaticJava);
|
||||
predicate(!((CallStaticJavaNode*) n)->is_method_handle_invoke());
|
||||
effect(USE meth);
|
||||
|
||||
ins_cost(300);
|
||||
@ -12540,6 +12575,28 @@ instruct CallStaticJavaDirect(method meth)
|
||||
ins_alignment(4);
|
||||
%}
|
||||
|
||||
// Call Java Static Instruction (method handle version)
|
||||
// Note: If this code changes, the corresponding ret_addr_offset() and
|
||||
// compute_padding() functions will have to be adjusted.
|
||||
instruct CallStaticJavaHandle(method meth, rbp_RegP rbp) %{
|
||||
match(CallStaticJava);
|
||||
predicate(((CallStaticJavaNode*) n)->is_method_handle_invoke());
|
||||
effect(USE meth);
|
||||
// RBP is saved by all callees (for interpreter stack correction).
|
||||
// We use it here for a similar purpose, in {preserve,restore}_SP.
|
||||
|
||||
ins_cost(300);
|
||||
format %{ "call,static/MethodHandle " %}
|
||||
opcode(0xE8); /* E8 cd */
|
||||
ins_encode(preserve_SP,
|
||||
Java_Static_Call(meth),
|
||||
restore_SP,
|
||||
call_epilog);
|
||||
ins_pipe(pipe_slow);
|
||||
ins_pc_relative(1);
|
||||
ins_alignment(4);
|
||||
%}
|
||||
|
||||
// Call Java Dynamic Instruction
|
||||
// Note: If this code changes, the corresponding ret_addr_offset() and
|
||||
// compute_padding() functions will have to be adjusted.
|
||||
|
@ -245,7 +245,7 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
if (handlerAddr == NULL) {
|
||||
CALL_VM_NOCHECK(InterpreterRuntime::prepare_native_call(thread, method));
|
||||
if (HAS_PENDING_EXCEPTION)
|
||||
goto unwind_and_return;
|
||||
goto unlock_unwind_and_return;
|
||||
|
||||
handlerAddr = method->signature_handler();
|
||||
assert(handlerAddr != NULL, "eh?");
|
||||
@ -254,7 +254,7 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
CALL_VM_NOCHECK(handlerAddr =
|
||||
InterpreterRuntime::slow_signature_handler(thread, method, NULL,NULL));
|
||||
if (HAS_PENDING_EXCEPTION)
|
||||
goto unwind_and_return;
|
||||
goto unlock_unwind_and_return;
|
||||
}
|
||||
handler = \
|
||||
InterpreterRuntime::SignatureHandler::from_handlerAddr(handlerAddr);
|
||||
@ -365,10 +365,10 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
|
||||
// Reset handle block
|
||||
thread->active_handles()->clear();
|
||||
|
||||
// Unlock if necessary. It seems totally wrong that this
|
||||
// is skipped in the event of an exception but apparently
|
||||
// the template interpreter does this so we do too.
|
||||
if (monitor && !HAS_PENDING_EXCEPTION) {
|
||||
unlock_unwind_and_return:
|
||||
|
||||
// Unlock if necessary
|
||||
if (monitor) {
|
||||
BasicLock *lock = monitor->lock();
|
||||
markOop header = lock->displaced_header();
|
||||
oop rcvr = monitor->obj();
|
||||
|
@ -251,8 +251,9 @@ class IRScopeDebugInfo: public CompilationResourceObj {
|
||||
DebugToken* expvals = recorder->create_scope_values(expressions());
|
||||
DebugToken* monvals = recorder->create_monitor_values(monitors());
|
||||
// reexecute allowed only for the topmost frame
|
||||
bool reexecute = topmost ? should_reexecute() : false;
|
||||
recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, locvals, expvals, monvals);
|
||||
bool reexecute = topmost ? should_reexecute() : false;
|
||||
bool is_method_handle_invoke = false;
|
||||
recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, locvals, expvals, monvals);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -425,7 +425,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
assert(exception.not_null(), "NULL exceptions should be handled by throw_exception");
|
||||
assert(exception->is_oop(), "just checking");
|
||||
// Check that exception is a subclass of Throwable, otherwise we have a VerifyError
|
||||
if (!(exception->is_a(SystemDictionary::throwable_klass()))) {
|
||||
if (!(exception->is_a(SystemDictionary::Throwable_klass()))) {
|
||||
if (ExitVMOnVerifyError) vm_exit(-1);
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
49
hotspot/src/share/vm/ci/ciCPCache.cpp
Normal file
49
hotspot/src/share/vm/ci/ciCPCache.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "incls/_precompiled.incl"
|
||||
#include "incls/_ciCPCache.cpp.incl"
|
||||
|
||||
// ciCPCache
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciCPCache::get_f1_offset
|
||||
size_t ciCPCache::get_f1_offset(int index) {
|
||||
// Calculate the offset from the constantPoolCacheOop to the f1
|
||||
// field.
|
||||
ByteSize f1_offset =
|
||||
constantPoolCacheOopDesc::entry_offset(index) +
|
||||
ConstantPoolCacheEntry::f1_offset();
|
||||
|
||||
return in_bytes(f1_offset);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciCPCache::print
|
||||
//
|
||||
// Print debugging information about the cache.
|
||||
void ciCPCache::print() {
|
||||
Unimplemented();
|
||||
}
|
43
hotspot/src/share/vm/ci/ciCPCache.hpp
Normal file
43
hotspot/src/share/vm/ci/ciCPCache.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// ciCPCache
|
||||
//
|
||||
// This class represents a constant pool cache.
|
||||
//
|
||||
// Note: This class is called ciCPCache as ciConstantPoolCache is used
|
||||
// for something different.
|
||||
class ciCPCache : public ciObject {
|
||||
public:
|
||||
ciCPCache(constantPoolCacheHandle cpcache) : ciObject(cpcache) {}
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_cpcache() const { return true; }
|
||||
|
||||
// Get the offset in bytes from the oop to the f1 field of the
|
||||
// requested entry.
|
||||
size_t get_f1_offset(int index);
|
||||
|
||||
void print();
|
||||
};
|
46
hotspot/src/share/vm/ci/ciCallSite.cpp
Normal file
46
hotspot/src/share/vm/ci/ciCallSite.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "incls/_precompiled.incl"
|
||||
#include "incls/_ciCallSite.cpp.incl"
|
||||
|
||||
// ciCallSite
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciCallSite::get_target
|
||||
//
|
||||
// Return the target MethodHandle of this CallSite.
|
||||
ciMethodHandle* ciCallSite::get_target() const {
|
||||
VM_ENTRY_MARK;
|
||||
oop method_handle_oop = java_dyn_CallSite::target(get_oop());
|
||||
return CURRENT_ENV->get_object(method_handle_oop)->as_method_handle();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciCallSite::print
|
||||
//
|
||||
// Print debugging information about the CallSite.
|
||||
void ciCallSite::print() {
|
||||
Unimplemented();
|
||||
}
|
39
hotspot/src/share/vm/ci/ciCallSite.hpp
Normal file
39
hotspot/src/share/vm/ci/ciCallSite.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// ciCallSite
|
||||
//
|
||||
// The class represents a java.dyn.CallSite object.
|
||||
class ciCallSite : public ciInstance {
|
||||
public:
|
||||
ciCallSite(instanceHandle h_i) : ciInstance(h_i) {}
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_call_site() const { return true; }
|
||||
|
||||
// Return the target MethodHandle of this CallSite.
|
||||
ciMethodHandle* get_target() const;
|
||||
|
||||
void print();
|
||||
};
|
@ -25,6 +25,7 @@
|
||||
class ciEnv;
|
||||
class ciObjectFactory;
|
||||
class ciConstantPoolCache;
|
||||
class ciCPCache;
|
||||
|
||||
class ciField;
|
||||
class ciConstant;
|
||||
@ -42,6 +43,8 @@ class ciTypeFlow;
|
||||
class ciObject;
|
||||
class ciNullObject;
|
||||
class ciInstance;
|
||||
class ciCallSite;
|
||||
class ciMethodHandle;
|
||||
class ciMethod;
|
||||
class ciMethodData;
|
||||
class ciReceiverTypeData; // part of ciMethodData
|
||||
@ -78,6 +81,7 @@ friend class ciObjectFactory;
|
||||
// Any more access must be given explicitly.
|
||||
#define CI_PACKAGE_ACCESS_TO \
|
||||
friend class ciObjectFactory; \
|
||||
friend class ciCallSite; \
|
||||
friend class ciConstantPoolCache; \
|
||||
friend class ciField; \
|
||||
friend class ciConstant; \
|
||||
@ -93,6 +97,7 @@ friend class ciNullObject; \
|
||||
friend class ciInstance; \
|
||||
friend class ciMethod; \
|
||||
friend class ciMethodData; \
|
||||
friend class ciMethodHandle; \
|
||||
friend class ciReceiverTypeData; \
|
||||
friend class ciSymbol; \
|
||||
friend class ciArray; \
|
||||
|
@ -38,17 +38,9 @@ ciInstanceKlassKlass* ciEnv::_instance_klass_klass_instance;
|
||||
ciTypeArrayKlassKlass* ciEnv::_type_array_klass_klass_instance;
|
||||
ciObjArrayKlassKlass* ciEnv::_obj_array_klass_klass_instance;
|
||||
|
||||
ciInstanceKlass* ciEnv::_ArrayStoreException;
|
||||
ciInstanceKlass* ciEnv::_Class;
|
||||
ciInstanceKlass* ciEnv::_ClassCastException;
|
||||
ciInstanceKlass* ciEnv::_Object;
|
||||
ciInstanceKlass* ciEnv::_Throwable;
|
||||
ciInstanceKlass* ciEnv::_Thread;
|
||||
ciInstanceKlass* ciEnv::_OutOfMemoryError;
|
||||
ciInstanceKlass* ciEnv::_String;
|
||||
ciInstanceKlass* ciEnv::_StringBuffer;
|
||||
ciInstanceKlass* ciEnv::_StringBuilder;
|
||||
ciInstanceKlass* ciEnv::_Integer;
|
||||
#define WK_KLASS_DEFN(name, ignore_s, ignore_o) ciInstanceKlass* ciEnv::_##name = NULL;
|
||||
WK_KLASSES_DO(WK_KLASS_DEFN)
|
||||
#undef WK_KLASS_DEFN
|
||||
|
||||
ciSymbol* ciEnv::_unloaded_cisymbol = NULL;
|
||||
ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL;
|
||||
@ -442,12 +434,11 @@ ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass,
|
||||
// ciEnv::get_klass_by_index_impl
|
||||
//
|
||||
// Implementation of get_klass_by_index.
|
||||
ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor,
|
||||
ciKlass* ciEnv::get_klass_by_index_impl(constantPoolHandle cpool,
|
||||
int index,
|
||||
bool& is_accessible) {
|
||||
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
|
||||
bool& is_accessible,
|
||||
ciInstanceKlass* accessor) {
|
||||
EXCEPTION_CONTEXT;
|
||||
constantPoolHandle cpool(THREAD, accessor->get_instanceKlass()->constants());
|
||||
KlassHandle klass (THREAD, constantPoolOopDesc::klass_at_if_loaded(cpool, index));
|
||||
symbolHandle klass_name;
|
||||
if (klass.is_null()) {
|
||||
@ -509,22 +500,21 @@ ciKlass* ciEnv::get_klass_by_index_impl(ciInstanceKlass* accessor,
|
||||
// ciEnv::get_klass_by_index
|
||||
//
|
||||
// Get a klass from the constant pool.
|
||||
ciKlass* ciEnv::get_klass_by_index(ciInstanceKlass* accessor,
|
||||
ciKlass* ciEnv::get_klass_by_index(constantPoolHandle cpool,
|
||||
int index,
|
||||
bool& is_accessible) {
|
||||
GUARDED_VM_ENTRY(return get_klass_by_index_impl(accessor, index, is_accessible);)
|
||||
bool& is_accessible,
|
||||
ciInstanceKlass* accessor) {
|
||||
GUARDED_VM_ENTRY(return get_klass_by_index_impl(cpool, index, is_accessible, accessor);)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciEnv::get_constant_by_index_impl
|
||||
//
|
||||
// Implementation of get_constant_by_index().
|
||||
ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor,
|
||||
int index) {
|
||||
ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
|
||||
int index,
|
||||
ciInstanceKlass* accessor) {
|
||||
EXCEPTION_CONTEXT;
|
||||
instanceKlass* ik_accessor = accessor->get_instanceKlass();
|
||||
assert(ik_accessor->is_linked(), "must be linked before accessing constant pool");
|
||||
constantPoolOop cpool = ik_accessor->constants();
|
||||
constantTag tag = cpool->tag_at(index);
|
||||
if (tag.is_int()) {
|
||||
return ciConstant(T_INT, (jint)cpool->int_at(index));
|
||||
@ -552,7 +542,7 @@ ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor,
|
||||
} else if (tag.is_klass() || tag.is_unresolved_klass()) {
|
||||
// 4881222: allow ldc to take a class type
|
||||
bool ignore;
|
||||
ciKlass* klass = get_klass_by_index_impl(accessor, index, ignore);
|
||||
ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore, accessor);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
record_out_of_memory_failure();
|
||||
@ -561,6 +551,11 @@ ciConstant ciEnv::get_constant_by_index_impl(ciInstanceKlass* accessor,
|
||||
assert (klass->is_instance_klass() || klass->is_array_klass(),
|
||||
"must be an instance or array klass ");
|
||||
return ciConstant(T_OBJECT, klass);
|
||||
} else if (tag.is_object()) {
|
||||
oop obj = cpool->object_at(index);
|
||||
assert(obj->is_instance(), "must be an instance");
|
||||
ciObject* ciobj = get_object(obj);
|
||||
return ciConstant(T_OBJECT, ciobj);
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
return ciConstant();
|
||||
@ -597,9 +592,10 @@ bool ciEnv::is_unresolved_klass_impl(instanceKlass* accessor, int index) const {
|
||||
// Pull a constant out of the constant pool. How appropriate.
|
||||
//
|
||||
// Implementation note: this query is currently in no way cached.
|
||||
ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor,
|
||||
int index) {
|
||||
GUARDED_VM_ENTRY(return get_constant_by_index_impl(accessor, index); )
|
||||
ciConstant ciEnv::get_constant_by_index(constantPoolHandle cpool,
|
||||
int index,
|
||||
ciInstanceKlass* accessor) {
|
||||
GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, index, accessor);)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -609,7 +605,7 @@ ciConstant ciEnv::get_constant_by_index(ciInstanceKlass* accessor,
|
||||
//
|
||||
// Implementation note: this query is currently in no way cached.
|
||||
bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
|
||||
int index) const {
|
||||
int index) const {
|
||||
GUARDED_VM_ENTRY(return is_unresolved_string_impl(accessor->get_instanceKlass(), index); )
|
||||
}
|
||||
|
||||
@ -620,7 +616,7 @@ bool ciEnv::is_unresolved_string(ciInstanceKlass* accessor,
|
||||
//
|
||||
// Implementation note: this query is currently in no way cached.
|
||||
bool ciEnv::is_unresolved_klass(ciInstanceKlass* accessor,
|
||||
int index) const {
|
||||
int index) const {
|
||||
GUARDED_VM_ENTRY(return is_unresolved_klass_impl(accessor->get_instanceKlass(), index); )
|
||||
}
|
||||
|
||||
@ -701,15 +697,12 @@ methodOop ciEnv::lookup_method(instanceKlass* accessor,
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciEnv::get_method_by_index_impl
|
||||
ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor,
|
||||
int index, Bytecodes::Code bc) {
|
||||
// Get the method's declared holder.
|
||||
|
||||
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
|
||||
constantPoolHandle cpool = accessor->get_instanceKlass()->constants();
|
||||
ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
|
||||
int index, Bytecodes::Code bc,
|
||||
ciInstanceKlass* accessor) {
|
||||
int holder_index = cpool->klass_ref_index_at(index);
|
||||
bool holder_is_accessible;
|
||||
ciKlass* holder = get_klass_by_index_impl(accessor, holder_index, holder_is_accessible);
|
||||
ciKlass* holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor);
|
||||
ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder);
|
||||
|
||||
// Get the method's name and signature.
|
||||
@ -735,6 +728,33 @@ ciMethod* ciEnv::get_method_by_index_impl(ciInstanceKlass* accessor,
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciEnv::get_fake_invokedynamic_method_impl
|
||||
ciMethod* ciEnv::get_fake_invokedynamic_method_impl(constantPoolHandle cpool,
|
||||
int index, Bytecodes::Code bc) {
|
||||
assert(bc == Bytecodes::_invokedynamic, "must be invokedynamic");
|
||||
|
||||
// Get the CallSite from the constant pool cache.
|
||||
ConstantPoolCacheEntry* cpc_entry = cpool->cache()->secondary_entry_at(index);
|
||||
assert(cpc_entry != NULL && cpc_entry->is_secondary_entry(), "sanity");
|
||||
Handle call_site = cpc_entry->f1();
|
||||
|
||||
// Call site might not be linked yet.
|
||||
if (call_site.is_null()) {
|
||||
ciInstanceKlass* mh_klass = get_object(SystemDictionary::MethodHandle_klass())->as_instance_klass();
|
||||
ciSymbol* sig_sym = get_object(cpool->signature_ref_at(index))->as_symbol();
|
||||
return get_unloaded_method(mh_klass, ciSymbol::invoke_name(), sig_sym);
|
||||
}
|
||||
|
||||
// Get the methodOop from the CallSite.
|
||||
methodOop method_oop = (methodOop) java_dyn_CallSite::vmmethod(call_site());
|
||||
assert(method_oop != NULL, "sanity");
|
||||
assert(method_oop->is_method_handle_invoke(), "consistent");
|
||||
|
||||
return get_object(method_oop)->as_method();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciEnv::get_instance_klass_for_declared_method_holder
|
||||
ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* method_holder) {
|
||||
@ -757,15 +777,19 @@ ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* m
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciEnv::get_method_by_index
|
||||
ciMethod* ciEnv::get_method_by_index(ciInstanceKlass* accessor,
|
||||
int index, Bytecodes::Code bc) {
|
||||
GUARDED_VM_ENTRY(return get_method_by_index_impl(accessor, index, bc);)
|
||||
ciMethod* ciEnv::get_method_by_index(constantPoolHandle cpool,
|
||||
int index, Bytecodes::Code bc,
|
||||
ciInstanceKlass* accessor) {
|
||||
if (bc == Bytecodes::_invokedynamic) {
|
||||
GUARDED_VM_ENTRY(return get_fake_invokedynamic_method_impl(cpool, index, bc);)
|
||||
} else {
|
||||
GUARDED_VM_ENTRY(return get_method_by_index_impl(cpool, index, bc, accessor);)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciEnv::name_buffer
|
||||
char *ciEnv::name_buffer(int req_len) {
|
||||
|
@ -74,17 +74,9 @@ private:
|
||||
static ciTypeArrayKlassKlass* _type_array_klass_klass_instance;
|
||||
static ciObjArrayKlassKlass* _obj_array_klass_klass_instance;
|
||||
|
||||
static ciInstanceKlass* _ArrayStoreException;
|
||||
static ciInstanceKlass* _Class;
|
||||
static ciInstanceKlass* _ClassCastException;
|
||||
static ciInstanceKlass* _Object;
|
||||
static ciInstanceKlass* _Throwable;
|
||||
static ciInstanceKlass* _Thread;
|
||||
static ciInstanceKlass* _OutOfMemoryError;
|
||||
static ciInstanceKlass* _String;
|
||||
static ciInstanceKlass* _StringBuffer;
|
||||
static ciInstanceKlass* _StringBuilder;
|
||||
static ciInstanceKlass* _Integer;
|
||||
#define WK_KLASS_DECL(name, ignore_s, ignore_o) static ciInstanceKlass* _##name;
|
||||
WK_KLASSES_DO(WK_KLASS_DECL)
|
||||
#undef WK_KLASS_DECL
|
||||
|
||||
static ciSymbol* _unloaded_cisymbol;
|
||||
static ciInstanceKlass* _unloaded_ciinstance_klass;
|
||||
@ -120,37 +112,45 @@ private:
|
||||
bool require_local);
|
||||
|
||||
// Constant pool access.
|
||||
ciKlass* get_klass_by_index(ciInstanceKlass* loading_klass,
|
||||
ciKlass* get_klass_by_index(constantPoolHandle cpool,
|
||||
int klass_index,
|
||||
bool& is_accessible);
|
||||
ciConstant get_constant_by_index(ciInstanceKlass* loading_klass,
|
||||
int constant_index);
|
||||
bool& is_accessible,
|
||||
ciInstanceKlass* loading_klass);
|
||||
ciConstant get_constant_by_index(constantPoolHandle cpool,
|
||||
int constant_index,
|
||||
ciInstanceKlass* accessor);
|
||||
bool is_unresolved_string(ciInstanceKlass* loading_klass,
|
||||
int constant_index) const;
|
||||
bool is_unresolved_klass(ciInstanceKlass* loading_klass,
|
||||
int constant_index) const;
|
||||
ciField* get_field_by_index(ciInstanceKlass* loading_klass,
|
||||
int field_index);
|
||||
ciMethod* get_method_by_index(ciInstanceKlass* loading_klass,
|
||||
int method_index, Bytecodes::Code bc);
|
||||
ciMethod* get_method_by_index(constantPoolHandle cpool,
|
||||
int method_index, Bytecodes::Code bc,
|
||||
ciInstanceKlass* loading_klass);
|
||||
|
||||
// Implementation methods for loading and constant pool access.
|
||||
ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||
ciSymbol* klass_name,
|
||||
bool require_local);
|
||||
ciKlass* get_klass_by_index_impl(ciInstanceKlass* loading_klass,
|
||||
ciKlass* get_klass_by_index_impl(constantPoolHandle cpool,
|
||||
int klass_index,
|
||||
bool& is_accessible);
|
||||
ciConstant get_constant_by_index_impl(ciInstanceKlass* loading_klass,
|
||||
int constant_index);
|
||||
bool& is_accessible,
|
||||
ciInstanceKlass* loading_klass);
|
||||
ciConstant get_constant_by_index_impl(constantPoolHandle cpool,
|
||||
int constant_index,
|
||||
ciInstanceKlass* loading_klass);
|
||||
bool is_unresolved_string_impl (instanceKlass* loading_klass,
|
||||
int constant_index) const;
|
||||
bool is_unresolved_klass_impl (instanceKlass* loading_klass,
|
||||
int constant_index) const;
|
||||
ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass,
|
||||
int field_index);
|
||||
ciMethod* get_method_by_index_impl(ciInstanceKlass* loading_klass,
|
||||
int method_index, Bytecodes::Code bc);
|
||||
ciMethod* get_method_by_index_impl(constantPoolHandle cpool,
|
||||
int method_index, Bytecodes::Code bc,
|
||||
ciInstanceKlass* loading_klass);
|
||||
ciMethod* get_fake_invokedynamic_method_impl(constantPoolHandle cpool,
|
||||
int index, Bytecodes::Code bc);
|
||||
|
||||
// Helper methods
|
||||
bool check_klass_accessibility(ciKlass* accessing_klass,
|
||||
@ -292,39 +292,13 @@ public:
|
||||
|
||||
|
||||
// Access to certain well known ciObjects.
|
||||
ciInstanceKlass* ArrayStoreException_klass() {
|
||||
return _ArrayStoreException;
|
||||
}
|
||||
ciInstanceKlass* Class_klass() {
|
||||
return _Class;
|
||||
}
|
||||
ciInstanceKlass* ClassCastException_klass() {
|
||||
return _ClassCastException;
|
||||
}
|
||||
ciInstanceKlass* Object_klass() {
|
||||
return _Object;
|
||||
}
|
||||
ciInstanceKlass* Throwable_klass() {
|
||||
return _Throwable;
|
||||
}
|
||||
ciInstanceKlass* Thread_klass() {
|
||||
return _Thread;
|
||||
}
|
||||
ciInstanceKlass* OutOfMemoryError_klass() {
|
||||
return _OutOfMemoryError;
|
||||
}
|
||||
ciInstanceKlass* String_klass() {
|
||||
return _String;
|
||||
}
|
||||
ciInstanceKlass* StringBuilder_klass() {
|
||||
return _StringBuilder;
|
||||
}
|
||||
ciInstanceKlass* StringBuffer_klass() {
|
||||
return _StringBuffer;
|
||||
}
|
||||
ciInstanceKlass* Integer_klass() {
|
||||
return _Integer;
|
||||
#define WK_KLASS_FUNC(name, ignore_s, ignore_o) \
|
||||
ciInstanceKlass* name() { \
|
||||
return _##name;\
|
||||
}
|
||||
WK_KLASSES_DO(WK_KLASS_FUNC)
|
||||
#undef WK_KLASS_FUNC
|
||||
|
||||
ciInstance* NullPointerException_instance() {
|
||||
assert(_NullPointerException_instance != NULL, "initialization problem");
|
||||
return _NullPointerException_instance;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2003 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,12 +34,16 @@
|
||||
//
|
||||
// Get the exception klass that this handler catches.
|
||||
ciInstanceKlass* ciExceptionHandler::catch_klass() {
|
||||
VM_ENTRY_MARK;
|
||||
assert(!is_catch_all(), "bad index");
|
||||
if (_catch_klass == NULL) {
|
||||
bool will_link;
|
||||
ciKlass* k = CURRENT_ENV->get_klass_by_index(_loading_klass,
|
||||
assert(_loading_klass->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
|
||||
constantPoolHandle cpool(_loading_klass->get_instanceKlass()->constants());
|
||||
ciKlass* k = CURRENT_ENV->get_klass_by_index(cpool,
|
||||
_catch_klass_index,
|
||||
will_link);
|
||||
will_link,
|
||||
_loading_klass);
|
||||
if (!will_link && k->is_loaded()) {
|
||||
GUARDED_VM_ENTRY(
|
||||
k = CURRENT_ENV->get_unloaded_klass(_loading_klass, k->name());
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -86,7 +86,7 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with(NULL) {
|
||||
bool ignore;
|
||||
// This is not really a class reference; the index always refers to the
|
||||
// field's type signature, as a symbol. Linkage checks do not apply.
|
||||
_type = ciEnv::current(thread)->get_klass_by_index(klass, sig_index, ignore);
|
||||
_type = ciEnv::current(thread)->get_klass_by_index(cpool, sig_index, ignore, klass);
|
||||
} else {
|
||||
_type = ciType::make(field_type);
|
||||
}
|
||||
@ -100,9 +100,9 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with(NULL) {
|
||||
int holder_index = cpool->klass_ref_index_at(index);
|
||||
bool holder_is_accessible;
|
||||
ciInstanceKlass* declared_holder =
|
||||
ciEnv::current(thread)->get_klass_by_index(klass, holder_index,
|
||||
holder_is_accessible)
|
||||
->as_instance_klass();
|
||||
ciEnv::current(thread)->get_klass_by_index(cpool, holder_index,
|
||||
holder_is_accessible,
|
||||
klass)->as_instance_klass();
|
||||
|
||||
// The declared holder of this field may not have been loaded.
|
||||
// Bail out with partial field information.
|
||||
@ -168,8 +168,18 @@ void ciField::initialize_from(fieldDescriptor* fd) {
|
||||
_holder = CURRENT_ENV->get_object(fd->field_holder())->as_instance_klass();
|
||||
|
||||
// Check to see if the field is constant.
|
||||
if (_holder->is_initialized() &&
|
||||
this->is_final() && this->is_static()) {
|
||||
if (_holder->is_initialized() && this->is_final()) {
|
||||
if (!this->is_static()) {
|
||||
// A field can be constant if it's a final static field or if it's
|
||||
// a final non-static field of a trusted class ({java,sun}.dyn).
|
||||
if (_holder->is_in_package("java/dyn") || _holder->is_in_package("sun/dyn")) {
|
||||
_is_constant = true;
|
||||
return;
|
||||
}
|
||||
_is_constant = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// This field just may be constant. The only cases where it will
|
||||
// not be constant are:
|
||||
//
|
||||
@ -182,8 +192,8 @@ void ciField::initialize_from(fieldDescriptor* fd) {
|
||||
// java.lang.System.out, and java.lang.System.err.
|
||||
|
||||
klassOop k = _holder->get_klassOop();
|
||||
assert( SystemDictionary::system_klass() != NULL, "Check once per vm");
|
||||
if( k == SystemDictionary::system_klass() ) {
|
||||
assert( SystemDictionary::System_klass() != NULL, "Check once per vm");
|
||||
if( k == SystemDictionary::System_klass() ) {
|
||||
// Check offsets for case 2: System.in, System.out, or System.err
|
||||
if( _offset == java_lang_System::in_offset_in_bytes() ||
|
||||
_offset == java_lang_System::out_offset_in_bytes() ||
|
||||
|
@ -138,10 +138,18 @@ public:
|
||||
|
||||
// Get the constant value of this field.
|
||||
ciConstant constant_value() {
|
||||
assert(is_constant(), "illegal call to constant_value()");
|
||||
assert(is_static() && is_constant(), "illegal call to constant_value()");
|
||||
return _constant_value;
|
||||
}
|
||||
|
||||
// Get the constant value of non-static final field in the given
|
||||
// object.
|
||||
ciConstant constant_value_of(ciObject* object) {
|
||||
assert(!is_static() && is_constant(), "only if field is non-static constant");
|
||||
assert(object->is_instance(), "must be instance");
|
||||
return object->as_instance()->field_value(this);
|
||||
}
|
||||
|
||||
// Check for link time errors. Accessing a field from a
|
||||
// certain class via a certain bytecode may or may not be legal.
|
||||
// This call checks to see if an exception may be raised by
|
||||
|
@ -36,7 +36,7 @@ ciType* ciInstance::java_mirror_type() {
|
||||
VM_ENTRY_MARK;
|
||||
oop m = get_oop();
|
||||
// Return NULL if it is not java.lang.Class.
|
||||
if (m == NULL || m->klass() != SystemDictionary::class_klass()) {
|
||||
if (m == NULL || m->klass() != SystemDictionary::Class_klass()) {
|
||||
return NULL;
|
||||
}
|
||||
// Return either a primitive type or a klass.
|
||||
|
@ -75,7 +75,7 @@ ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) :
|
||||
_java_mirror = NULL;
|
||||
|
||||
if (is_shared()) {
|
||||
if (h_k() != SystemDictionary::object_klass()) {
|
||||
if (h_k() != SystemDictionary::Object_klass()) {
|
||||
super();
|
||||
}
|
||||
java_mirror();
|
||||
@ -232,8 +232,48 @@ bool ciInstanceKlass::is_java_lang_Object() {
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstanceKlass::uses_default_loader
|
||||
bool ciInstanceKlass::uses_default_loader() {
|
||||
VM_ENTRY_MARK;
|
||||
return loader() == NULL;
|
||||
// Note: We do not need to resolve the handle or enter the VM
|
||||
// in order to test null-ness.
|
||||
return _loader == NULL;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstanceKlass::is_in_package
|
||||
//
|
||||
// Is this klass in the given package?
|
||||
bool ciInstanceKlass::is_in_package(const char* packagename, int len) {
|
||||
// To avoid class loader mischief, this test always rejects application classes.
|
||||
if (!uses_default_loader())
|
||||
return false;
|
||||
GUARDED_VM_ENTRY(
|
||||
return is_in_package_impl(packagename, len);
|
||||
)
|
||||
}
|
||||
|
||||
bool ciInstanceKlass::is_in_package_impl(const char* packagename, int len) {
|
||||
ASSERT_IN_VM;
|
||||
|
||||
// If packagename contains trailing '/' exclude it from the
|
||||
// prefix-test since we test for it explicitly.
|
||||
if (packagename[len - 1] == '/')
|
||||
len--;
|
||||
|
||||
if (!name()->starts_with(packagename, len))
|
||||
return false;
|
||||
|
||||
// Test if the class name is something like "java/lang".
|
||||
if ((len + 1) > name()->utf8_length())
|
||||
return false;
|
||||
|
||||
// Test for trailing '/'
|
||||
if ((char) name()->byte_at(len) != '/')
|
||||
return false;
|
||||
|
||||
// Make sure it's not actually in a subpackage:
|
||||
if (name()->index_of_at(len+1, "/", 1) >= 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
@ -29,10 +29,11 @@
|
||||
// be loaded.
|
||||
class ciInstanceKlass : public ciKlass {
|
||||
CI_PACKAGE_ACCESS
|
||||
friend class ciBytecodeStream;
|
||||
friend class ciEnv;
|
||||
friend class ciExceptionHandler;
|
||||
friend class ciMethod;
|
||||
friend class ciField;
|
||||
friend class ciBytecodeStream;
|
||||
|
||||
private:
|
||||
jobject _loader;
|
||||
@ -78,6 +79,8 @@ protected:
|
||||
|
||||
const char* type_string() { return "ciInstanceKlass"; }
|
||||
|
||||
bool is_in_package_impl(const char* packagename, int len);
|
||||
|
||||
void print_impl(outputStream* st);
|
||||
|
||||
ciConstantPoolCache* field_cache();
|
||||
@ -196,6 +199,12 @@ public:
|
||||
|
||||
bool is_java_lang_Object();
|
||||
|
||||
// Is this klass in the given package?
|
||||
bool is_in_package(const char* packagename) {
|
||||
return is_in_package(packagename, (int) strlen(packagename));
|
||||
}
|
||||
bool is_in_package(const char* packagename, int len);
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_instance_klass() { return true; }
|
||||
bool is_java_klass() { return true; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -69,7 +69,7 @@ public:
|
||||
ciKlass(KlassHandle k_h);
|
||||
|
||||
// What is the name of this klass?
|
||||
ciSymbol* name() { return _name; }
|
||||
ciSymbol* name() const { return _name; }
|
||||
|
||||
// What is its layout helper value?
|
||||
jint layout_helper() { return _layout_helper; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -687,7 +687,7 @@ int ciMethod::scale_count(int count, float prof_factor) {
|
||||
// ------------------------------------------------------------------
|
||||
// invokedynamic support
|
||||
//
|
||||
bool ciMethod::is_method_handle_invoke() {
|
||||
bool ciMethod::is_method_handle_invoke() const {
|
||||
check_is_loaded();
|
||||
bool flag = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS);
|
||||
#ifdef ASSERT
|
||||
@ -700,6 +700,12 @@ bool ciMethod::is_method_handle_invoke() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
bool ciMethod::is_method_handle_adapter() const {
|
||||
check_is_loaded();
|
||||
VM_ENTRY_MARK;
|
||||
return get_methodOop()->is_method_handle_adapter();
|
||||
}
|
||||
|
||||
ciInstance* ciMethod::method_handle_type() {
|
||||
check_is_loaded();
|
||||
VM_ENTRY_MARK;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,6 +38,8 @@ class ciMethod : public ciObject {
|
||||
CI_PACKAGE_ACCESS
|
||||
friend class ciEnv;
|
||||
friend class ciExceptionHandlerStream;
|
||||
friend class ciBytecodeStream;
|
||||
friend class ciMethodHandle;
|
||||
|
||||
private:
|
||||
// General method information.
|
||||
@ -213,7 +215,10 @@ class ciMethod : public ciObject {
|
||||
bool check_call(int refinfo_index, bool is_static) const;
|
||||
void build_method_data(); // make sure it exists in the VM also
|
||||
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
|
||||
bool is_method_handle_invoke();
|
||||
|
||||
// JSR 292 support
|
||||
bool is_method_handle_invoke() const;
|
||||
bool is_method_handle_adapter() const;
|
||||
ciInstance* method_handle_type();
|
||||
|
||||
// What kind of ciObject is this?
|
||||
@ -251,4 +256,10 @@ class ciMethod : public ciObject {
|
||||
// Print the name of this method in various incarnations.
|
||||
void print_name(outputStream* st = tty);
|
||||
void print_short_name(outputStream* st = tty);
|
||||
|
||||
methodOop get_method_handle_target() {
|
||||
klassOop receiver_limit_oop = NULL;
|
||||
int flags = 0;
|
||||
return MethodHandles::decode_method(get_oop(), receiver_limit_oop, flags);
|
||||
}
|
||||
};
|
||||
|
52
hotspot/src/share/vm/ci/ciMethodHandle.cpp
Normal file
52
hotspot/src/share/vm/ci/ciMethodHandle.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "incls/_precompiled.incl"
|
||||
#include "incls/_ciMethodHandle.cpp.incl"
|
||||
|
||||
// ciMethodHandle
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethodHandle::get_adapter
|
||||
//
|
||||
// Return an adapter for this MethodHandle.
|
||||
ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const {
|
||||
VM_ENTRY_MARK;
|
||||
|
||||
Handle h(get_oop());
|
||||
methodHandle callee(_callee->get_methodOop());
|
||||
MethodHandleCompiler mhc(h, callee, is_invokedynamic, THREAD);
|
||||
methodHandle m = mhc.compile(CHECK_NULL);
|
||||
return CURRENT_ENV->get_object(m())->as_method();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethodHandle::print_impl
|
||||
//
|
||||
// Implementation of the print method.
|
||||
void ciMethodHandle::print_impl(outputStream* st) {
|
||||
st->print(" type=");
|
||||
get_oop()->print();
|
||||
}
|
56
hotspot/src/share/vm/ci/ciMethodHandle.hpp
Normal file
56
hotspot/src/share/vm/ci/ciMethodHandle.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// ciMethodHandle
|
||||
//
|
||||
// The class represents a java.dyn.MethodHandle object.
|
||||
class ciMethodHandle : public ciInstance {
|
||||
private:
|
||||
ciMethod* _callee;
|
||||
|
||||
// Return an adapter for this MethodHandle.
|
||||
ciMethod* get_adapter(bool is_invokedynamic) const;
|
||||
|
||||
protected:
|
||||
void print_impl(outputStream* st);
|
||||
|
||||
public:
|
||||
ciMethodHandle(instanceHandle h_i) : ciInstance(h_i) {};
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_method_handle() const { return true; }
|
||||
|
||||
ciMethod* callee() const { return _callee; }
|
||||
void set_callee(ciMethod* m) { _callee = m; }
|
||||
|
||||
// Return an adapter for a MethodHandle call.
|
||||
ciMethod* get_method_handle_adapter() const {
|
||||
return get_adapter(false);
|
||||
}
|
||||
|
||||
// Return an adapter for an invokedynamic call.
|
||||
ciMethod* get_invokedynamic_adapter() const {
|
||||
return get_adapter(true);
|
||||
}
|
||||
};
|
@ -131,9 +131,12 @@ public:
|
||||
|
||||
// What kind of ciObject is this?
|
||||
virtual bool is_null_object() const { return false; }
|
||||
virtual bool is_call_site() const { return false; }
|
||||
virtual bool is_cpcache() const { return false; }
|
||||
virtual bool is_instance() { return false; }
|
||||
virtual bool is_method() { return false; }
|
||||
virtual bool is_method_data() { return false; }
|
||||
virtual bool is_method_handle() const { return false; }
|
||||
virtual bool is_array() { return false; }
|
||||
virtual bool is_obj_array() { return false; }
|
||||
virtual bool is_type_array() { return false; }
|
||||
@ -185,6 +188,14 @@ public:
|
||||
assert(is_null_object(), "bad cast");
|
||||
return (ciNullObject*)this;
|
||||
}
|
||||
ciCallSite* as_call_site() {
|
||||
assert(is_call_site(), "bad cast");
|
||||
return (ciCallSite*) this;
|
||||
}
|
||||
ciCPCache* as_cpcache() {
|
||||
assert(is_cpcache(), "bad cast");
|
||||
return (ciCPCache*) this;
|
||||
}
|
||||
ciInstance* as_instance() {
|
||||
assert(is_instance(), "bad cast");
|
||||
return (ciInstance*)this;
|
||||
@ -197,6 +208,10 @@ public:
|
||||
assert(is_method_data(), "bad cast");
|
||||
return (ciMethodData*)this;
|
||||
}
|
||||
ciMethodHandle* as_method_handle() {
|
||||
assert(is_method_handle(), "bad cast");
|
||||
return (ciMethodHandle*) this;
|
||||
}
|
||||
ciArray* as_array() {
|
||||
assert(is_array(), "bad cast");
|
||||
return (ciArray*)this;
|
||||
|
@ -144,39 +144,13 @@ void ciObjectFactory::init_shared_objects() {
|
||||
ciEnv::_obj_array_klass_klass_instance =
|
||||
get(Universe::objArrayKlassKlassObj())
|
||||
->as_obj_array_klass_klass();
|
||||
ciEnv::_ArrayStoreException =
|
||||
get(SystemDictionary::ArrayStoreException_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_Class =
|
||||
get(SystemDictionary::class_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_ClassCastException =
|
||||
get(SystemDictionary::ClassCastException_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_Object =
|
||||
get(SystemDictionary::object_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_Throwable =
|
||||
get(SystemDictionary::throwable_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_Thread =
|
||||
get(SystemDictionary::thread_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_OutOfMemoryError =
|
||||
get(SystemDictionary::OutOfMemoryError_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_String =
|
||||
get(SystemDictionary::string_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_StringBuffer =
|
||||
get(SystemDictionary::stringBuffer_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_StringBuilder =
|
||||
get(SystemDictionary::StringBuilder_klass())
|
||||
->as_instance_klass();
|
||||
ciEnv::_Integer =
|
||||
get(SystemDictionary::int_klass())
|
||||
->as_instance_klass();
|
||||
|
||||
#define WK_KLASS_DEFN(name, ignore_s, opt) \
|
||||
if (SystemDictionary::name() != NULL) \
|
||||
ciEnv::_##name = get(SystemDictionary::name())->as_instance_klass();
|
||||
|
||||
WK_KLASSES_DO(WK_KLASS_DEFN)
|
||||
#undef WK_KLASS_DEFN
|
||||
|
||||
for (int len = -1; len != _ci_objects->length(); ) {
|
||||
len = _ci_objects->length();
|
||||
@ -333,13 +307,21 @@ ciObject* ciObjectFactory::create_new_object(oop o) {
|
||||
return new (arena()) ciMethodData(h_md);
|
||||
} else if (o->is_instance()) {
|
||||
instanceHandle h_i(THREAD, (instanceOop)o);
|
||||
return new (arena()) ciInstance(h_i);
|
||||
if (java_dyn_CallSite::is_instance(o))
|
||||
return new (arena()) ciCallSite(h_i);
|
||||
else if (java_dyn_MethodHandle::is_instance(o))
|
||||
return new (arena()) ciMethodHandle(h_i);
|
||||
else
|
||||
return new (arena()) ciInstance(h_i);
|
||||
} else if (o->is_objArray()) {
|
||||
objArrayHandle h_oa(THREAD, (objArrayOop)o);
|
||||
return new (arena()) ciObjArray(h_oa);
|
||||
} else if (o->is_typeArray()) {
|
||||
typeArrayHandle h_ta(THREAD, (typeArrayOop)o);
|
||||
return new (arena()) ciTypeArray(h_ta);
|
||||
} else if (o->is_constantPoolCache()) {
|
||||
constantPoolCacheHandle h_cpc(THREAD, (constantPoolCacheOop) o);
|
||||
return new (arena()) ciCPCache(h_cpc);
|
||||
}
|
||||
|
||||
// The oop is of some type not supported by the compiler interface.
|
||||
@ -576,7 +558,7 @@ ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) {
|
||||
if (key->is_perm() && _non_perm_count == 0) {
|
||||
return emptyBucket;
|
||||
} else if (key->is_instance()) {
|
||||
if (key->klass() == SystemDictionary::class_klass()) {
|
||||
if (key->klass() == SystemDictionary::Class_klass()) {
|
||||
// class mirror instances are always perm
|
||||
return emptyBucket;
|
||||
}
|
||||
|
@ -186,8 +186,9 @@ int ciBytecodeStream::get_klass_index() const {
|
||||
// If this bytecode is a new, newarray, multianewarray, instanceof,
|
||||
// or checkcast, get the referenced klass.
|
||||
ciKlass* ciBytecodeStream::get_klass(bool& will_link) {
|
||||
return CURRENT_ENV->get_klass_by_index(_holder, get_klass_index(),
|
||||
will_link);
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolHandle cpool(_method->get_methodOop()->constants());
|
||||
return CURRENT_ENV->get_klass_by_index(cpool, get_klass_index(), will_link, _holder);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -213,7 +214,9 @@ int ciBytecodeStream::get_constant_index() const {
|
||||
// If this bytecode is one of the ldc variants, get the referenced
|
||||
// constant.
|
||||
ciConstant ciBytecodeStream::get_constant() {
|
||||
return CURRENT_ENV->get_constant_by_index(_holder, get_constant_index());
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolHandle cpool(_method->get_methodOop()->constants());
|
||||
return CURRENT_ENV->get_constant_by_index(cpool, get_constant_index(), _holder);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -264,9 +267,11 @@ ciField* ciBytecodeStream::get_field(bool& will_link) {
|
||||
// There is no "will_link" result passed back. The user is responsible
|
||||
// for checking linkability when retrieving the associated field.
|
||||
ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolHandle cpool(_method->get_methodOop()->constants());
|
||||
int holder_index = get_field_holder_index();
|
||||
bool ignore;
|
||||
return CURRENT_ENV->get_klass_by_index(_holder, holder_index, ignore)
|
||||
return CURRENT_ENV->get_klass_by_index(cpool, holder_index, ignore, _holder)
|
||||
->as_instance_klass();
|
||||
}
|
||||
|
||||
@ -277,9 +282,10 @@ ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
|
||||
// referenced by the current bytecode. Used for generating
|
||||
// deoptimization information.
|
||||
int ciBytecodeStream::get_field_holder_index() {
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
|
||||
return cpool->klass_ref_index_at(get_field_index());
|
||||
GUARDED_VM_ENTRY(
|
||||
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
|
||||
return cpool->klass_ref_index_at(get_field_index());
|
||||
)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -321,7 +327,9 @@ int ciBytecodeStream::get_method_index() {
|
||||
//
|
||||
// If this is a method invocation bytecode, get the invoked method.
|
||||
ciMethod* ciBytecodeStream::get_method(bool& will_link) {
|
||||
ciMethod* m = CURRENT_ENV->get_method_by_index(_holder, get_method_index(),cur_bc());
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolHandle cpool(_method->get_methodOop()->constants());
|
||||
ciMethod* m = CURRENT_ENV->get_method_by_index(cpool, get_method_index(), cur_bc(), _holder);
|
||||
will_link = m->is_loaded();
|
||||
return m;
|
||||
}
|
||||
@ -338,11 +346,13 @@ ciMethod* ciBytecodeStream::get_method(bool& will_link) {
|
||||
// There is no "will_link" result passed back. The user is responsible
|
||||
// for checking linkability when retrieving the associated method.
|
||||
ciKlass* ciBytecodeStream::get_declared_method_holder() {
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolHandle cpool(_method->get_methodOop()->constants());
|
||||
bool ignore;
|
||||
// report as Dynamic for invokedynamic, which is syntactically classless
|
||||
// report as InvokeDynamic for invokedynamic, which is syntactically classless
|
||||
if (cur_bc() == Bytecodes::_invokedynamic)
|
||||
return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_Dynamic(), false);
|
||||
return CURRENT_ENV->get_klass_by_index(_holder, get_method_holder_index(), ignore);
|
||||
return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_InvokeDynamic(), false);
|
||||
return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
@ -352,8 +362,7 @@ ciKlass* ciBytecodeStream::get_declared_method_holder() {
|
||||
// referenced by the current bytecode. Used for generating
|
||||
// deoptimization information.
|
||||
int ciBytecodeStream::get_method_holder_index() {
|
||||
VM_ENTRY_MARK;
|
||||
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
|
||||
constantPoolOop cpool = _method->get_methodOop()->constants();
|
||||
return cpool->klass_ref_index_at(get_method_index());
|
||||
}
|
||||
|
||||
@ -370,3 +379,31 @@ int ciBytecodeStream::get_method_signature_index() {
|
||||
int name_and_type_index = cpool->name_and_type_ref_index_at(method_index);
|
||||
return cpool->signature_ref_index_at(name_and_type_index);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciBytecodeStream::get_cpcache
|
||||
ciCPCache* ciBytecodeStream::get_cpcache() {
|
||||
VM_ENTRY_MARK;
|
||||
// Get the constant pool.
|
||||
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
|
||||
constantPoolCacheOop cpcache = cpool->cache();
|
||||
|
||||
return CURRENT_ENV->get_object(cpcache)->as_cpcache();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciBytecodeStream::get_call_site
|
||||
ciCallSite* ciBytecodeStream::get_call_site() {
|
||||
VM_ENTRY_MARK;
|
||||
// Get the constant pool.
|
||||
constantPoolOop cpool = _holder->get_instanceKlass()->constants();
|
||||
constantPoolCacheOop cpcache = cpool->cache();
|
||||
|
||||
// Get the CallSite from the constant pool cache.
|
||||
int method_index = get_method_index();
|
||||
ConstantPoolCacheEntry* cpcache_entry = cpcache->secondary_entry_at(method_index);
|
||||
oop call_site_oop = cpcache_entry->f1();
|
||||
|
||||
// Create a CallSite object and return it.
|
||||
return CURRENT_ENV->get_object(call_site_oop)->as_call_site();
|
||||
}
|
||||
|
@ -232,6 +232,9 @@ public:
|
||||
int get_method_holder_index();
|
||||
int get_method_signature_index();
|
||||
|
||||
ciCPCache* get_cpcache();
|
||||
ciCallSite* get_call_site();
|
||||
|
||||
private:
|
||||
void assert_index_size(int required_size) const {
|
||||
#ifdef ASSERT
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -59,6 +59,22 @@ int ciSymbol::byte_at(int i) {
|
||||
GUARDED_VM_ENTRY(return get_symbolOop()->byte_at(i);)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciSymbol::starts_with
|
||||
//
|
||||
// Tests if the symbol starts with the given prefix.
|
||||
bool ciSymbol::starts_with(const char* prefix, int len) const {
|
||||
GUARDED_VM_ENTRY(return get_symbolOop()->starts_with(prefix, len);)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciSymbol::index_of
|
||||
//
|
||||
// Determines where the symbol contains the given substring.
|
||||
int ciSymbol::index_of_at(int i, const char* str, int len) const {
|
||||
GUARDED_VM_ENTRY(return get_symbolOop()->index_of_at(i, str, len);)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciSymbol::utf8_length
|
||||
int ciSymbol::utf8_length() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,6 +28,7 @@
|
||||
// machine.
|
||||
class ciSymbol : public ciObject {
|
||||
CI_PACKAGE_ACCESS
|
||||
// These friends all make direct use of get_symbolOop:
|
||||
friend class ciEnv;
|
||||
friend class ciInstanceKlass;
|
||||
friend class ciSignature;
|
||||
@ -38,13 +39,13 @@ private:
|
||||
ciSymbol(symbolOop s) : ciObject(s) {}
|
||||
ciSymbol(symbolHandle s); // for use with vmSymbolHandles
|
||||
|
||||
symbolOop get_symbolOop() { return (symbolOop)get_oop(); }
|
||||
symbolOop get_symbolOop() const { return (symbolOop)get_oop(); }
|
||||
|
||||
const char* type_string() { return "ciSymbol"; }
|
||||
|
||||
void print_impl(outputStream* st);
|
||||
|
||||
int byte_at(int i);
|
||||
// This is public in symbolOop but private here, because the base can move:
|
||||
jbyte* base();
|
||||
|
||||
// Make a ciSymbol from a C string (implementation).
|
||||
@ -55,6 +56,15 @@ public:
|
||||
const char* as_utf8();
|
||||
int utf8_length();
|
||||
|
||||
// Return the i-th utf8 byte, where i < utf8_length
|
||||
int byte_at(int i);
|
||||
|
||||
// Tests if the symbol starts with the given prefix.
|
||||
bool starts_with(const char* prefix, int len) const;
|
||||
|
||||
// Determines where the symbol contains the given substring.
|
||||
int index_of_at(int i, const char* str, int len) const;
|
||||
|
||||
// What kind of ciObject is this?
|
||||
bool is_symbol() { return true; }
|
||||
|
||||
|
@ -111,7 +111,7 @@ ciType* ciType::make(BasicType t) {
|
||||
// short, etc.
|
||||
// Note: Bare T_ADDRESS means a raw pointer type, not a return_address.
|
||||
assert((uint)t < T_CONFLICT+1, "range check");
|
||||
if (t == T_OBJECT) return ciEnv::_Object; // java/lang/Object
|
||||
if (t == T_OBJECT) return ciEnv::_Object_klass; // java/lang/Object
|
||||
assert(_basic_types[t] != NULL, "domain check");
|
||||
return _basic_types[t];
|
||||
}
|
||||
|
@ -635,8 +635,15 @@ void ciTypeFlow::StateVector::do_invoke(ciBytecodeStream* str,
|
||||
ciMethod* method = str->get_method(will_link);
|
||||
if (!will_link) {
|
||||
// We weren't able to find the method.
|
||||
ciKlass* unloaded_holder = method->holder();
|
||||
trap(str, unloaded_holder, str->get_method_holder_index());
|
||||
if (str->cur_bc() == Bytecodes::_invokedynamic) {
|
||||
trap(str, NULL,
|
||||
Deoptimization::make_trap_request
|
||||
(Deoptimization::Reason_uninitialized,
|
||||
Deoptimization::Action_reinterpret));
|
||||
} else {
|
||||
ciKlass* unloaded_holder = method->holder();
|
||||
trap(str, unloaded_holder, str->get_method_holder_index());
|
||||
}
|
||||
} else {
|
||||
ciSignature* signature = method->signature();
|
||||
ciSignatureStream sigstr(signature);
|
||||
@ -1292,8 +1299,8 @@ bool ciTypeFlow::StateVector::apply_one_bytecode(ciBytecodeStream* str) {
|
||||
case Bytecodes::_invokeinterface: do_invoke(str, true); break;
|
||||
case Bytecodes::_invokespecial: do_invoke(str, true); break;
|
||||
case Bytecodes::_invokestatic: do_invoke(str, false); break;
|
||||
|
||||
case Bytecodes::_invokevirtual: do_invoke(str, true); break;
|
||||
case Bytecodes::_invokedynamic: do_invoke(str, false); break;
|
||||
|
||||
case Bytecodes::_istore: store_local_int(str->get_index()); break;
|
||||
case Bytecodes::_istore_0: store_local_int(0); break;
|
||||
|
@ -79,7 +79,7 @@
|
||||
THREAD); \
|
||||
if (HAS_PENDING_EXCEPTION) { \
|
||||
if (PENDING_EXCEPTION->klass() == \
|
||||
SystemDictionary::threaddeath_klass()) { \
|
||||
SystemDictionary::ThreadDeath_klass()) { \
|
||||
/* Kill the compilation. */ \
|
||||
fatal("unhandled ci exception"); \
|
||||
return (result); \
|
||||
|
@ -430,7 +430,7 @@ void ClassFileParser::patch_constant_pool(constantPoolHandle cp, int index, Hand
|
||||
case JVM_CONSTANT_UnresolvedClass :
|
||||
// Patching a class means pre-resolving it.
|
||||
// The name in the constant pool is ignored.
|
||||
if (patch->klass() == SystemDictionary::class_klass()) { // %%% java_lang_Class::is_instance
|
||||
if (patch->klass() == SystemDictionary::Class_klass()) { // %%% java_lang_Class::is_instance
|
||||
guarantee_property(!java_lang_Class::is_primitive(patch()),
|
||||
"Illegal class patch at %d in class file %s",
|
||||
index, CHECK);
|
||||
@ -643,7 +643,7 @@ void ClassFileParser::verify_constantvalue(int constantvalue_index, int signatur
|
||||
guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK);
|
||||
break;
|
||||
case T_OBJECT:
|
||||
guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;", 18)
|
||||
guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
|
||||
&& (value_type.is_string() || value_type.is_unresolved_string())),
|
||||
"Bad string initial value in class file %s", CHECK);
|
||||
break;
|
||||
@ -1718,9 +1718,7 @@ methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interf
|
||||
m->set_exception_table(exception_handlers());
|
||||
|
||||
// Copy byte codes
|
||||
if (code_length > 0) {
|
||||
memcpy(m->code_base(), code_start, code_length);
|
||||
}
|
||||
m->set_code(code_start);
|
||||
|
||||
// Copy line number table
|
||||
if (linenumber_table != NULL) {
|
||||
@ -3471,8 +3469,8 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) {
|
||||
#endif
|
||||
|
||||
// Check if this klass supports the java.lang.Cloneable interface
|
||||
if (SystemDictionary::cloneable_klass_loaded()) {
|
||||
if (k->is_subtype_of(SystemDictionary::cloneable_klass())) {
|
||||
if (SystemDictionary::Cloneable_klass_loaded()) {
|
||||
if (k->is_subtype_of(SystemDictionary::Cloneable_klass())) {
|
||||
k->set_is_cloneable();
|
||||
}
|
||||
}
|
||||
@ -4178,7 +4176,7 @@ char* ClassFileParser::skip_over_field_name(char* name, bool slash_ok, unsigned
|
||||
// Check if ch is Java identifier start or is Java identifier part
|
||||
// 4672820: call java.lang.Character methods directly without generating separate tables.
|
||||
EXCEPTION_MARK;
|
||||
instanceKlassHandle klass (THREAD, SystemDictionary::char_klass());
|
||||
instanceKlassHandle klass (THREAD, SystemDictionary::Character_klass());
|
||||
|
||||
// return value
|
||||
JavaValue result(T_BOOLEAN);
|
||||
|
@ -819,7 +819,7 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) {
|
||||
_package_hash_table->copy_pkgnames(packages);
|
||||
}
|
||||
// Allocate objArray and fill with java.lang.String
|
||||
objArrayOop r = oopFactory::new_objArray(SystemDictionary::string_klass(),
|
||||
objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(),
|
||||
nof_entries, CHECK_0);
|
||||
objArrayHandle result(THREAD, r);
|
||||
for (int i = 0; i < nof_entries; i++) {
|
||||
|
@ -95,14 +95,14 @@ oop JavaAssertions::createAssertionStatusDirectives(TRAPS) {
|
||||
int len;
|
||||
typeArrayOop t;
|
||||
len = OptionList::count(_packages);
|
||||
objArrayOop pn = oopFactory::new_objArray(SystemDictionary::string_klass(), len, CHECK_NULL);
|
||||
objArrayOop pn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL);
|
||||
objArrayHandle pkgNames (THREAD, pn);
|
||||
t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
|
||||
typeArrayHandle pkgEnabled(THREAD, t);
|
||||
fillJavaArrays(_packages, len, pkgNames, pkgEnabled, CHECK_NULL);
|
||||
|
||||
len = OptionList::count(_classes);
|
||||
objArrayOop cn = oopFactory::new_objArray(SystemDictionary::string_klass(), len, CHECK_NULL);
|
||||
objArrayOop cn = oopFactory::new_objArray(SystemDictionary::String_klass(), len, CHECK_NULL);
|
||||
objArrayHandle classNames (THREAD, cn);
|
||||
t = oopFactory::new_typeArray(T_BOOLEAN, len, CHECK_NULL);
|
||||
typeArrayHandle classEnabled(THREAD, t);
|
||||
|
@ -68,9 +68,9 @@ Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
|
||||
// and the char array it points to end up in the same cache line.
|
||||
oop obj;
|
||||
if (tenured) {
|
||||
obj = instanceKlass::cast(SystemDictionary::string_klass())->allocate_permanent_instance(CHECK_NH);
|
||||
obj = instanceKlass::cast(SystemDictionary::String_klass())->allocate_permanent_instance(CHECK_NH);
|
||||
} else {
|
||||
obj = instanceKlass::cast(SystemDictionary::string_klass())->allocate_instance(CHECK_NH);
|
||||
obj = instanceKlass::cast(SystemDictionary::String_klass())->allocate_instance(CHECK_NH);
|
||||
}
|
||||
|
||||
// Create the char array. The String object must be handlized here
|
||||
@ -293,7 +293,7 @@ char* java_lang_String::as_utf8_string(oop java_string, int start, int len) {
|
||||
|
||||
bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
|
||||
assert(SharedSkipVerify ||
|
||||
java_string->klass() == SystemDictionary::string_klass(),
|
||||
java_string->klass() == SystemDictionary::String_klass(),
|
||||
"must be java_string");
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int offset = java_lang_String::offset(java_string);
|
||||
@ -311,7 +311,7 @@ bool java_lang_String::equals(oop java_string, jchar* chars, int len) {
|
||||
|
||||
void java_lang_String::print(Handle java_string, outputStream* st) {
|
||||
oop obj = java_string();
|
||||
assert(obj->klass() == SystemDictionary::string_klass(), "must be java_string");
|
||||
assert(obj->klass() == SystemDictionary::String_klass(), "must be java_string");
|
||||
typeArrayOop value = java_lang_String::value(obj);
|
||||
int offset = java_lang_String::offset(obj);
|
||||
int length = java_lang_String::length(obj);
|
||||
@ -339,9 +339,9 @@ oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) {
|
||||
// class is put into the system dictionary.
|
||||
int computed_modifiers = k->compute_modifier_flags(CHECK_0);
|
||||
k->set_modifier_flags(computed_modifiers);
|
||||
if (SystemDictionary::class_klass_loaded()) {
|
||||
if (SystemDictionary::Class_klass_loaded()) {
|
||||
// Allocate mirror (java.lang.Class instance)
|
||||
Handle mirror = instanceKlass::cast(SystemDictionary::class_klass())->allocate_permanent_instance(CHECK_0);
|
||||
Handle mirror = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0);
|
||||
// Setup indirections
|
||||
mirror->obj_field_put(klass_offset, k());
|
||||
k->set_java_mirror(mirror());
|
||||
@ -378,7 +378,7 @@ oop java_lang_Class::create_mirror(KlassHandle k, TRAPS) {
|
||||
oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
|
||||
// This should be improved by adding a field at the Java level or by
|
||||
// introducing a new VM klass (see comment in ClassFileParser)
|
||||
oop java_class = instanceKlass::cast(SystemDictionary::class_klass())->allocate_permanent_instance(CHECK_0);
|
||||
oop java_class = instanceKlass::cast(SystemDictionary::Class_klass())->allocate_permanent_instance(CHECK_0);
|
||||
if (type != T_VOID) {
|
||||
klassOop aklass = Universe::typeArrayKlassObj(type);
|
||||
assert(aklass != NULL, "correct bootstrap");
|
||||
@ -502,7 +502,7 @@ BasicType java_lang_Class::as_BasicType(oop java_class, klassOop* reference_klas
|
||||
|
||||
oop java_lang_Class::primitive_mirror(BasicType t) {
|
||||
oop mirror = Universe::java_mirror(t);
|
||||
assert(mirror != NULL && mirror->is_a(SystemDictionary::class_klass()), "must be a Class");
|
||||
assert(mirror != NULL && mirror->is_a(SystemDictionary::Class_klass()), "must be a Class");
|
||||
assert(java_lang_Class::is_primitive(mirror), "must be primitive");
|
||||
return mirror;
|
||||
}
|
||||
@ -515,14 +515,14 @@ void java_lang_Class::compute_offsets() {
|
||||
assert(!offsets_computed, "offsets should be initialized only once");
|
||||
offsets_computed = true;
|
||||
|
||||
klassOop k = SystemDictionary::class_klass();
|
||||
klassOop k = SystemDictionary::Class_klass();
|
||||
// The classRedefinedCount field is only present starting in 1.5,
|
||||
// so don't go fatal.
|
||||
compute_optional_offset(classRedefinedCount_offset,
|
||||
k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
|
||||
|
||||
// The field indicating parallelCapable (parallelLockMap) is only present starting in 7,
|
||||
klassOop k1 = SystemDictionary::classloader_klass();
|
||||
klassOop k1 = SystemDictionary::ClassLoader_klass();
|
||||
compute_optional_offset(parallelCapable_offset,
|
||||
k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature());
|
||||
}
|
||||
@ -588,7 +588,7 @@ int java_lang_Thread::_park_event_offset = 0 ;
|
||||
void java_lang_Thread::compute_offsets() {
|
||||
assert(_group_offset == 0, "offsets should be initialized only once");
|
||||
|
||||
klassOop k = SystemDictionary::thread_klass();
|
||||
klassOop k = SystemDictionary::Thread_klass();
|
||||
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::char_array_signature());
|
||||
compute_offset(_group_offset, k, vmSymbols::group_name(), vmSymbols::threadgroup_signature());
|
||||
compute_offset(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), vmSymbols::classloader_signature());
|
||||
@ -847,7 +847,7 @@ bool java_lang_ThreadGroup::is_vmAllowSuspension(oop java_thread_group) {
|
||||
void java_lang_ThreadGroup::compute_offsets() {
|
||||
assert(_parent_offset == 0, "offsets should be initialized only once");
|
||||
|
||||
klassOop k = SystemDictionary::threadGroup_klass();
|
||||
klassOop k = SystemDictionary::ThreadGroup_klass();
|
||||
|
||||
compute_offset(_parent_offset, k, vmSymbols::parent_name(), vmSymbols::threadgroup_signature());
|
||||
compute_offset(_name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
|
||||
@ -1344,7 +1344,7 @@ void java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(Handle t
|
||||
// No-op if stack trace is disabled
|
||||
if (!StackTraceInThrowable) return;
|
||||
|
||||
assert(throwable->is_a(SystemDictionary::throwable_klass()), "sanity check");
|
||||
assert(throwable->is_a(SystemDictionary::Throwable_klass()), "sanity check");
|
||||
|
||||
oop backtrace = java_lang_Throwable::backtrace(throwable());
|
||||
assert(backtrace != NULL, "backtrace not preallocated");
|
||||
@ -1449,7 +1449,7 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) {
|
||||
assert(JDK_Version::is_gte_jdk14x_version(), "should only be called in >= 1.4");
|
||||
|
||||
// Allocate java.lang.StackTraceElement instance
|
||||
klassOop k = SystemDictionary::stackTraceElement_klass();
|
||||
klassOop k = SystemDictionary::StackTraceElement_klass();
|
||||
assert(k != NULL, "must be loaded in 1.4+");
|
||||
instanceKlassHandle ik (THREAD, k);
|
||||
if (ik->should_be_initialized()) {
|
||||
@ -1487,7 +1487,7 @@ oop java_lang_StackTraceElement::create(methodHandle method, int bci, TRAPS) {
|
||||
|
||||
|
||||
void java_lang_reflect_AccessibleObject::compute_offsets() {
|
||||
klassOop k = SystemDictionary::reflect_accessible_object_klass();
|
||||
klassOop k = SystemDictionary::reflect_AccessibleObject_klass();
|
||||
compute_offset(override_offset, k, vmSymbols::override_name(), vmSymbols::bool_signature());
|
||||
}
|
||||
|
||||
@ -1502,7 +1502,7 @@ void java_lang_reflect_AccessibleObject::set_override(oop reflect, jboolean valu
|
||||
}
|
||||
|
||||
void java_lang_reflect_Method::compute_offsets() {
|
||||
klassOop k = SystemDictionary::reflect_method_klass();
|
||||
klassOop k = SystemDictionary::reflect_Method_klass();
|
||||
compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
|
||||
compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
|
||||
compute_offset(returnType_offset, k, vmSymbols::returnType_name(), vmSymbols::class_signature());
|
||||
@ -1523,7 +1523,7 @@ void java_lang_reflect_Method::compute_offsets() {
|
||||
|
||||
Handle java_lang_reflect_Method::create(TRAPS) {
|
||||
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
|
||||
klassOop klass = SystemDictionary::reflect_method_klass();
|
||||
klassOop klass = SystemDictionary::reflect_Method_klass();
|
||||
// This class is eagerly initialized during VM initialization, since we keep a refence
|
||||
// to one of the methods
|
||||
assert(instanceKlass::cast(klass)->is_initialized(), "must be initialized");
|
||||
@ -1665,7 +1665,7 @@ void java_lang_reflect_Method::set_annotation_default(oop method, oop value) {
|
||||
}
|
||||
|
||||
void java_lang_reflect_Constructor::compute_offsets() {
|
||||
klassOop k = SystemDictionary::reflect_constructor_klass();
|
||||
klassOop k = SystemDictionary::reflect_Constructor_klass();
|
||||
compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
|
||||
compute_offset(parameterTypes_offset, k, vmSymbols::parameterTypes_name(), vmSymbols::class_array_signature());
|
||||
compute_offset(exceptionTypes_offset, k, vmSymbols::exceptionTypes_name(), vmSymbols::class_array_signature());
|
||||
@ -1789,7 +1789,7 @@ void java_lang_reflect_Constructor::set_parameter_annotations(oop method, oop va
|
||||
}
|
||||
|
||||
void java_lang_reflect_Field::compute_offsets() {
|
||||
klassOop k = SystemDictionary::reflect_field_klass();
|
||||
klassOop k = SystemDictionary::reflect_Field_klass();
|
||||
compute_offset(clazz_offset, k, vmSymbols::clazz_name(), vmSymbols::class_signature());
|
||||
compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature());
|
||||
compute_offset(type_offset, k, vmSymbols::type_name(), vmSymbols::class_signature());
|
||||
@ -1896,7 +1896,7 @@ void java_lang_reflect_Field::set_annotations(oop field, oop value) {
|
||||
|
||||
|
||||
void sun_reflect_ConstantPool::compute_offsets() {
|
||||
klassOop k = SystemDictionary::reflect_constant_pool_klass();
|
||||
klassOop k = SystemDictionary::reflect_ConstantPool_klass();
|
||||
// This null test can be removed post beta
|
||||
if (k != NULL) {
|
||||
compute_offset(_cp_oop_offset, k, vmSymbols::constantPoolOop_name(), vmSymbols::object_signature());
|
||||
@ -1906,7 +1906,7 @@ void sun_reflect_ConstantPool::compute_offsets() {
|
||||
|
||||
Handle sun_reflect_ConstantPool::create(TRAPS) {
|
||||
assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem");
|
||||
klassOop k = SystemDictionary::reflect_constant_pool_klass();
|
||||
klassOop k = SystemDictionary::reflect_ConstantPool_klass();
|
||||
instanceKlassHandle klass (THREAD, k);
|
||||
// Ensure it is initialized
|
||||
klass->initialize(CHECK_NH);
|
||||
@ -1926,7 +1926,7 @@ void sun_reflect_ConstantPool::set_cp_oop(oop reflect, oop value) {
|
||||
}
|
||||
|
||||
void sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets() {
|
||||
klassOop k = SystemDictionary::reflect_unsafe_static_field_accessor_impl_klass();
|
||||
klassOop k = SystemDictionary::reflect_UnsafeStaticFieldAccessorImpl_klass();
|
||||
// This null test can be removed post beta
|
||||
if (k != NULL) {
|
||||
compute_offset(_base_offset, k,
|
||||
@ -2072,7 +2072,7 @@ void java_lang_boxing_object::print(BasicType type, jvalue* value, outputStream*
|
||||
|
||||
// Support for java_lang_ref_Reference
|
||||
oop java_lang_ref_Reference::pending_list_lock() {
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass());
|
||||
char *addr = (((char *)ik->start_of_static_fields()) + static_lock_offset);
|
||||
if (UseCompressedOops) {
|
||||
return oopDesc::load_decode_heap_oop((narrowOop *)addr);
|
||||
@ -2082,7 +2082,7 @@ oop java_lang_ref_Reference::pending_list_lock() {
|
||||
}
|
||||
|
||||
HeapWord *java_lang_ref_Reference::pending_list_addr() {
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::reference_klass());
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::Reference_klass());
|
||||
char *addr = (((char *)ik->start_of_static_fields()) + static_pending_offset);
|
||||
// XXX This might not be HeapWord aligned, almost rather be char *.
|
||||
return (HeapWord*)addr;
|
||||
@ -2105,17 +2105,17 @@ jlong java_lang_ref_SoftReference::timestamp(oop ref) {
|
||||
}
|
||||
|
||||
jlong java_lang_ref_SoftReference::clock() {
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::soft_reference_klass());
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass());
|
||||
int offset = ik->offset_of_static_fields() + static_clock_offset;
|
||||
|
||||
return SystemDictionary::soft_reference_klass()->long_field(offset);
|
||||
return SystemDictionary::SoftReference_klass()->long_field(offset);
|
||||
}
|
||||
|
||||
void java_lang_ref_SoftReference::set_clock(jlong value) {
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::soft_reference_klass());
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::SoftReference_klass());
|
||||
int offset = ik->offset_of_static_fields() + static_clock_offset;
|
||||
|
||||
SystemDictionary::soft_reference_klass()->long_field_put(offset, value);
|
||||
SystemDictionary::SoftReference_klass()->long_field_put(offset, value);
|
||||
}
|
||||
|
||||
|
||||
@ -2403,6 +2403,10 @@ oop java_dyn_MethodType::ptype(oop mt, int idx) {
|
||||
return ptypes(mt)->obj_at(idx);
|
||||
}
|
||||
|
||||
int java_dyn_MethodType::ptype_count(oop mt) {
|
||||
return ptypes(mt)->length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Support for java_dyn_MethodTypeForm
|
||||
@ -2534,7 +2538,7 @@ oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
|
||||
// the generated bytecodes for reflection, and if so, "magically"
|
||||
// delegate to its parent to prevent class loading from occurring
|
||||
// in places where applications using reflection didn't expect it.
|
||||
klassOop delegating_cl_class = SystemDictionary::reflect_delegating_classloader_klass();
|
||||
klassOop delegating_cl_class = SystemDictionary::reflect_DelegatingClassLoader_klass();
|
||||
// This might be null in non-1.4 JDKs
|
||||
if (delegating_cl_class != NULL && loader->is_a(delegating_cl_class)) {
|
||||
return parent(loader);
|
||||
@ -2549,7 +2553,7 @@ oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
|
||||
void java_lang_System::compute_offsets() {
|
||||
assert(offset_of_static_fields == 0, "offsets should be initialized only once");
|
||||
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::system_klass());
|
||||
instanceKlass* ik = instanceKlass::cast(SystemDictionary::System_klass());
|
||||
offset_of_static_fields = ik->offset_of_static_fields();
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ class java_lang_String : AllStatic {
|
||||
|
||||
// Testers
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && obj->klass() == SystemDictionary::string_klass();
|
||||
return obj != NULL && obj->klass() == SystemDictionary::String_klass();
|
||||
}
|
||||
|
||||
// Debugging
|
||||
@ -161,7 +161,7 @@ class java_lang_Class : AllStatic {
|
||||
static void print_signature(oop java_class, outputStream *st);
|
||||
// Testing
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && obj->klass() == SystemDictionary::class_klass();
|
||||
return obj != NULL && obj->klass() == SystemDictionary::Class_klass();
|
||||
}
|
||||
static bool is_primitive(oop java_class);
|
||||
static BasicType primitive_type(oop java_class);
|
||||
@ -1027,6 +1027,7 @@ class java_dyn_MethodType: AllStatic {
|
||||
static oop form(oop mt);
|
||||
|
||||
static oop ptype(oop mt, int index);
|
||||
static int ptype_count(oop mt);
|
||||
|
||||
static symbolOop as_signature(oop mt, bool intern_if_not_found, TRAPS);
|
||||
static void print_signature(oop mt, outputStream* st);
|
||||
@ -1083,6 +1084,14 @@ public:
|
||||
static oop vmmethod(oop site);
|
||||
static void set_vmmethod(oop site, oop ref);
|
||||
|
||||
// Testers
|
||||
static bool is_subclass(klassOop klass) {
|
||||
return Klass::cast(klass)->is_subclass_of(SystemDictionary::CallSite_klass());
|
||||
}
|
||||
static bool is_instance(oop obj) {
|
||||
return obj != NULL && is_subclass(obj->klass());
|
||||
}
|
||||
|
||||
// Accessors for code generation:
|
||||
static int target_offset_in_bytes() { return _target_offset; }
|
||||
static int type_offset_in_bytes() { return _type_offset; }
|
||||
|
@ -60,10 +60,10 @@ oop SystemDictionary::java_system_loader() {
|
||||
}
|
||||
|
||||
void SystemDictionary::compute_java_system_loader(TRAPS) {
|
||||
KlassHandle system_klass(THREAD, WK_KLASS(classloader_klass));
|
||||
KlassHandle system_klass(THREAD, WK_KLASS(ClassLoader_klass));
|
||||
JavaValue result(T_OBJECT);
|
||||
JavaCalls::call_static(&result,
|
||||
KlassHandle(THREAD, WK_KLASS(classloader_klass)),
|
||||
KlassHandle(THREAD, WK_KLASS(ClassLoader_klass)),
|
||||
vmSymbolHandles::getSystemClassLoader_name(),
|
||||
vmSymbolHandles::void_classloader_signature(),
|
||||
CHECK);
|
||||
@ -128,7 +128,7 @@ klassOop SystemDictionary::handle_resolution_exception(symbolHandle class_name,
|
||||
// in which case we have to check whether the pending exception is a ClassNotFoundException,
|
||||
// and if so convert it to a NoClassDefFoundError
|
||||
// And chain the original ClassNotFoundException
|
||||
if (throw_error && PENDING_EXCEPTION->is_a(SystemDictionary::classNotFoundException_klass())) {
|
||||
if (throw_error && PENDING_EXCEPTION->is_a(SystemDictionary::ClassNotFoundException_klass())) {
|
||||
ResourceMark rm(THREAD);
|
||||
assert(klass_h() == NULL, "Should not have result with exception pending");
|
||||
Handle e(THREAD, PENDING_EXCEPTION);
|
||||
@ -359,7 +359,7 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass,
|
||||
|
||||
assert(class_loader() != NULL, "should not have non-null protection domain for null classloader");
|
||||
|
||||
KlassHandle system_loader(THREAD, SystemDictionary::classloader_klass());
|
||||
KlassHandle system_loader(THREAD, SystemDictionary::ClassLoader_klass());
|
||||
JavaCalls::call_special(&result,
|
||||
class_loader,
|
||||
system_loader,
|
||||
@ -743,7 +743,7 @@ klassOop SystemDictionary::resolve_instance_class_or_null(symbolHandle class_nam
|
||||
// Bootstrap goes through here to allow for an extra guarantee check
|
||||
if (UnsyncloadClass || (class_loader.is_null())) {
|
||||
if (k.is_null() && HAS_PENDING_EXCEPTION
|
||||
&& PENDING_EXCEPTION->is_a(SystemDictionary::linkageError_klass())) {
|
||||
&& PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
|
||||
MutexLocker mu(SystemDictionary_lock, THREAD);
|
||||
klassOop check = find_class(d_index, d_hash, name, class_loader);
|
||||
if (check != NULL) {
|
||||
@ -1367,7 +1367,7 @@ instanceKlassHandle SystemDictionary::load_instance_class(symbolHandle class_nam
|
||||
|
||||
JavaValue result(T_OBJECT);
|
||||
|
||||
KlassHandle spec_klass (THREAD, SystemDictionary::classloader_klass());
|
||||
KlassHandle spec_klass (THREAD, SystemDictionary::ClassLoader_klass());
|
||||
|
||||
// Call public unsynchronized loadClass(String) directly for all class loaders
|
||||
// for parallelCapable class loaders. JDK >=7, loadClass(String, boolean) will
|
||||
@ -1944,13 +1944,13 @@ void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id
|
||||
|
||||
|
||||
void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
||||
assert(WK_KLASS(object_klass) == NULL, "preloaded classes should only be initialized once");
|
||||
assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once");
|
||||
// Preload commonly used klasses
|
||||
WKID scan = FIRST_WKID;
|
||||
// first do Object, String, Class
|
||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(class_klass), scan, CHECK);
|
||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Class_klass), scan, CHECK);
|
||||
|
||||
debug_only(instanceKlass::verify_class_klass_nonstatic_oop_maps(WK_KLASS(class_klass)));
|
||||
debug_only(instanceKlass::verify_class_klass_nonstatic_oop_maps(WK_KLASS(Class_klass)));
|
||||
|
||||
// Fixup mirrors for classes loaded before java.lang.Class.
|
||||
// These calls iterate over the objects currently in the perm gen
|
||||
@ -1961,17 +1961,17 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
||||
Universe::fixup_mirrors(CHECK);
|
||||
|
||||
// do a bunch more:
|
||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(reference_klass), scan, CHECK);
|
||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(Reference_klass), scan, CHECK);
|
||||
|
||||
// Preload ref klasses and set reference types
|
||||
instanceKlass::cast(WK_KLASS(reference_klass))->set_reference_type(REF_OTHER);
|
||||
instanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(reference_klass));
|
||||
instanceKlass::cast(WK_KLASS(Reference_klass))->set_reference_type(REF_OTHER);
|
||||
instanceRefKlass::update_nonstatic_oop_maps(WK_KLASS(Reference_klass));
|
||||
|
||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(phantom_reference_klass), scan, CHECK);
|
||||
instanceKlass::cast(WK_KLASS(soft_reference_klass))->set_reference_type(REF_SOFT);
|
||||
instanceKlass::cast(WK_KLASS(weak_reference_klass))->set_reference_type(REF_WEAK);
|
||||
instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
|
||||
instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
|
||||
initialize_wk_klasses_through(WK_KLASS_ENUM_NAME(PhantomReference_klass), scan, CHECK);
|
||||
instanceKlass::cast(WK_KLASS(SoftReference_klass))->set_reference_type(REF_SOFT);
|
||||
instanceKlass::cast(WK_KLASS(WeakReference_klass))->set_reference_type(REF_WEAK);
|
||||
instanceKlass::cast(WK_KLASS(FinalReference_klass))->set_reference_type(REF_FINAL);
|
||||
instanceKlass::cast(WK_KLASS(PhantomReference_klass))->set_reference_type(REF_PHANTOM);
|
||||
|
||||
WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
|
||||
WKID meth_group_end = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
|
||||
@ -1984,7 +1984,7 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
||||
scan = WKID(meth_group_end+1);
|
||||
}
|
||||
WKID indy_group_start = WK_KLASS_ENUM_NAME(Linkage_klass);
|
||||
WKID indy_group_end = WK_KLASS_ENUM_NAME(Dynamic_klass);
|
||||
WKID indy_group_end = WK_KLASS_ENUM_NAME(InvokeDynamic_klass);
|
||||
initialize_wk_klasses_until(indy_group_start, scan, CHECK);
|
||||
if (EnableInvokeDynamic) {
|
||||
initialize_wk_klasses_through(indy_group_end, scan, CHECK);
|
||||
@ -1996,14 +1996,14 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
||||
|
||||
initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
|
||||
|
||||
_box_klasses[T_BOOLEAN] = WK_KLASS(boolean_klass);
|
||||
_box_klasses[T_CHAR] = WK_KLASS(char_klass);
|
||||
_box_klasses[T_FLOAT] = WK_KLASS(float_klass);
|
||||
_box_klasses[T_DOUBLE] = WK_KLASS(double_klass);
|
||||
_box_klasses[T_BYTE] = WK_KLASS(byte_klass);
|
||||
_box_klasses[T_SHORT] = WK_KLASS(short_klass);
|
||||
_box_klasses[T_INT] = WK_KLASS(int_klass);
|
||||
_box_klasses[T_LONG] = WK_KLASS(long_klass);
|
||||
_box_klasses[T_BOOLEAN] = WK_KLASS(Boolean_klass);
|
||||
_box_klasses[T_CHAR] = WK_KLASS(Character_klass);
|
||||
_box_klasses[T_FLOAT] = WK_KLASS(Float_klass);
|
||||
_box_klasses[T_DOUBLE] = WK_KLASS(Double_klass);
|
||||
_box_klasses[T_BYTE] = WK_KLASS(Byte_klass);
|
||||
_box_klasses[T_SHORT] = WK_KLASS(Short_klass);
|
||||
_box_klasses[T_INT] = WK_KLASS(Integer_klass);
|
||||
_box_klasses[T_LONG] = WK_KLASS(Long_klass);
|
||||
//_box_klasses[T_OBJECT] = WK_KLASS(object_klass);
|
||||
//_box_klasses[T_ARRAY] = WK_KLASS(object_klass);
|
||||
|
||||
@ -2014,11 +2014,11 @@ void SystemDictionary::initialize_preloaded_classes(TRAPS) {
|
||||
#endif // KERNEL
|
||||
|
||||
{ // Compute whether we should use loadClass or loadClassInternal when loading classes.
|
||||
methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature());
|
||||
methodOop method = instanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::loadClassInternal_name(), vmSymbols::string_class_signature());
|
||||
_has_loadClassInternal = (method != NULL);
|
||||
}
|
||||
{ // Compute whether we should use checkPackageAccess or NOT
|
||||
methodOop method = instanceKlass::cast(classloader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature());
|
||||
methodOop method = instanceKlass::cast(ClassLoader_klass())->find_method(vmSymbols::checkPackageAccess_name(), vmSymbols::class_protectiondomain_signature());
|
||||
_has_checkPackageAccess = (method != NULL);
|
||||
}
|
||||
}
|
||||
@ -2340,6 +2340,8 @@ methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature,
|
||||
SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature);
|
||||
if (spe == NULL || spe->property_oop() == NULL) {
|
||||
// Must create lots of stuff here, but outside of the SystemDictionary lock.
|
||||
if (THREAD->is_Compiler_thread())
|
||||
return NULL; // do not attempt from within compiler
|
||||
Handle mt = compute_method_handle_type(signature(),
|
||||
class_loader, protection_domain,
|
||||
CHECK_NULL);
|
||||
@ -2372,7 +2374,7 @@ Handle SystemDictionary::compute_method_handle_type(symbolHandle signature,
|
||||
TRAPS) {
|
||||
Handle empty;
|
||||
int npts = ArgumentCount(signature()).size();
|
||||
objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::class_klass(), npts, CHECK_(empty));
|
||||
objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::Class_klass(), npts, CHECK_(empty));
|
||||
int arg = 0;
|
||||
Handle rt; // the return type from the signature
|
||||
for (SignatureStream ss(signature()); !ss.is_done(); ss.next()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -82,55 +82,55 @@ class SymbolPropertyTable;
|
||||
|
||||
#define WK_KLASSES_DO(template) \
|
||||
/* well-known classes */ \
|
||||
template(object_klass, java_lang_Object, Pre) \
|
||||
template(string_klass, java_lang_String, Pre) \
|
||||
template(class_klass, java_lang_Class, Pre) \
|
||||
template(cloneable_klass, java_lang_Cloneable, Pre) \
|
||||
template(classloader_klass, java_lang_ClassLoader, Pre) \
|
||||
template(serializable_klass, java_io_Serializable, Pre) \
|
||||
template(system_klass, java_lang_System, Pre) \
|
||||
template(throwable_klass, java_lang_Throwable, Pre) \
|
||||
template(error_klass, java_lang_Error, Pre) \
|
||||
template(threaddeath_klass, java_lang_ThreadDeath, Pre) \
|
||||
template(exception_klass, java_lang_Exception, Pre) \
|
||||
template(runtime_exception_klass, java_lang_RuntimeException, Pre) \
|
||||
template(protectionDomain_klass, java_security_ProtectionDomain, Pre) \
|
||||
template(Object_klass, java_lang_Object, Pre) \
|
||||
template(String_klass, java_lang_String, Pre) \
|
||||
template(Class_klass, java_lang_Class, Pre) \
|
||||
template(Cloneable_klass, java_lang_Cloneable, Pre) \
|
||||
template(ClassLoader_klass, java_lang_ClassLoader, Pre) \
|
||||
template(Serializable_klass, java_io_Serializable, Pre) \
|
||||
template(System_klass, java_lang_System, Pre) \
|
||||
template(Throwable_klass, java_lang_Throwable, Pre) \
|
||||
template(Error_klass, java_lang_Error, Pre) \
|
||||
template(ThreadDeath_klass, java_lang_ThreadDeath, Pre) \
|
||||
template(Exception_klass, java_lang_Exception, Pre) \
|
||||
template(RuntimeException_klass, java_lang_RuntimeException, Pre) \
|
||||
template(ProtectionDomain_klass, java_security_ProtectionDomain, Pre) \
|
||||
template(AccessControlContext_klass, java_security_AccessControlContext, Pre) \
|
||||
template(classNotFoundException_klass, java_lang_ClassNotFoundException, Pre) \
|
||||
template(noClassDefFoundError_klass, java_lang_NoClassDefFoundError, Pre) \
|
||||
template(linkageError_klass, java_lang_LinkageError, Pre) \
|
||||
template(ClassNotFoundException_klass, java_lang_ClassNotFoundException, Pre) \
|
||||
template(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError, Pre) \
|
||||
template(LinkageError_klass, java_lang_LinkageError, Pre) \
|
||||
template(ClassCastException_klass, java_lang_ClassCastException, Pre) \
|
||||
template(ArrayStoreException_klass, java_lang_ArrayStoreException, Pre) \
|
||||
template(virtualMachineError_klass, java_lang_VirtualMachineError, Pre) \
|
||||
template(VirtualMachineError_klass, java_lang_VirtualMachineError, Pre) \
|
||||
template(OutOfMemoryError_klass, java_lang_OutOfMemoryError, Pre) \
|
||||
template(StackOverflowError_klass, java_lang_StackOverflowError, Pre) \
|
||||
template(IllegalMonitorStateException_klass, java_lang_IllegalMonitorStateException, Pre) \
|
||||
template(reference_klass, java_lang_ref_Reference, Pre) \
|
||||
template(Reference_klass, java_lang_ref_Reference, Pre) \
|
||||
\
|
||||
/* Preload ref klasses and set reference types */ \
|
||||
template(soft_reference_klass, java_lang_ref_SoftReference, Pre) \
|
||||
template(weak_reference_klass, java_lang_ref_WeakReference, Pre) \
|
||||
template(final_reference_klass, java_lang_ref_FinalReference, Pre) \
|
||||
template(phantom_reference_klass, java_lang_ref_PhantomReference, Pre) \
|
||||
template(finalizer_klass, java_lang_ref_Finalizer, Pre) \
|
||||
template(SoftReference_klass, java_lang_ref_SoftReference, Pre) \
|
||||
template(WeakReference_klass, java_lang_ref_WeakReference, Pre) \
|
||||
template(FinalReference_klass, java_lang_ref_FinalReference, Pre) \
|
||||
template(PhantomReference_klass, java_lang_ref_PhantomReference, Pre) \
|
||||
template(Finalizer_klass, java_lang_ref_Finalizer, Pre) \
|
||||
\
|
||||
template(thread_klass, java_lang_Thread, Pre) \
|
||||
template(threadGroup_klass, java_lang_ThreadGroup, Pre) \
|
||||
template(properties_klass, java_util_Properties, Pre) \
|
||||
template(reflect_accessible_object_klass, java_lang_reflect_AccessibleObject, Pre) \
|
||||
template(reflect_field_klass, java_lang_reflect_Field, Pre) \
|
||||
template(reflect_method_klass, java_lang_reflect_Method, Pre) \
|
||||
template(reflect_constructor_klass, java_lang_reflect_Constructor, Pre) \
|
||||
template(Thread_klass, java_lang_Thread, Pre) \
|
||||
template(ThreadGroup_klass, java_lang_ThreadGroup, Pre) \
|
||||
template(Properties_klass, java_util_Properties, Pre) \
|
||||
template(reflect_AccessibleObject_klass, java_lang_reflect_AccessibleObject, Pre) \
|
||||
template(reflect_Field_klass, java_lang_reflect_Field, Pre) \
|
||||
template(reflect_Method_klass, java_lang_reflect_Method, Pre) \
|
||||
template(reflect_Constructor_klass, java_lang_reflect_Constructor, Pre) \
|
||||
\
|
||||
/* NOTE: needed too early in bootstrapping process to have checks based on JDK version */ \
|
||||
/* Universe::is_gte_jdk14x_version() is not set up by this point. */ \
|
||||
/* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \
|
||||
template(reflect_magic_klass, sun_reflect_MagicAccessorImpl, Opt) \
|
||||
template(reflect_method_accessor_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \
|
||||
template(reflect_constructor_accessor_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \
|
||||
template(reflect_delegating_classloader_klass, sun_reflect_DelegatingClassLoader, Opt) \
|
||||
template(reflect_constant_pool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \
|
||||
template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
|
||||
template(reflect_MagicAccessorImpl_klass, sun_reflect_MagicAccessorImpl, Opt) \
|
||||
template(reflect_MethodAccessorImpl_klass, sun_reflect_MethodAccessorImpl, Opt_Only_JDK14NewRef) \
|
||||
template(reflect_ConstructorAccessorImpl_klass, sun_reflect_ConstructorAccessorImpl, Opt_Only_JDK14NewRef) \
|
||||
template(reflect_DelegatingClassLoader_klass, sun_reflect_DelegatingClassLoader, Opt) \
|
||||
template(reflect_ConstantPool_klass, sun_reflect_ConstantPool, Opt_Only_JDK15) \
|
||||
template(reflect_UnsafeStaticFieldAccessorImpl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
|
||||
\
|
||||
/* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
|
||||
template(MethodHandle_klass, java_dyn_MethodHandle, Opt) \
|
||||
@ -144,16 +144,14 @@ class SymbolPropertyTable;
|
||||
template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
|
||||
template(Linkage_klass, java_dyn_Linkage, Opt) \
|
||||
template(CallSite_klass, java_dyn_CallSite, Opt) \
|
||||
template(Dynamic_klass, java_dyn_Dynamic, Opt) \
|
||||
/* Note: MethodHandle must be first, and Dynamic last in group */ \
|
||||
template(InvokeDynamic_klass, java_dyn_InvokeDynamic, Opt) \
|
||||
/* Note: MethodHandle must be first, and InvokeDynamic last in group */ \
|
||||
\
|
||||
template(vector_klass, java_util_Vector, Pre) \
|
||||
template(hashtable_klass, java_util_Hashtable, Pre) \
|
||||
template(stringBuffer_klass, java_lang_StringBuffer, Pre) \
|
||||
template(StringBuffer_klass, java_lang_StringBuffer, Pre) \
|
||||
template(StringBuilder_klass, java_lang_StringBuilder, Pre) \
|
||||
\
|
||||
/* It's NULL in non-1.4 JDKs. */ \
|
||||
template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \
|
||||
template(StackTraceElement_klass, java_lang_StackTraceElement, Opt) \
|
||||
/* Universe::is_gte_jdk14x_version() is not set up by this point. */ \
|
||||
/* It's okay if this turns out to be NULL in non-1.4 JDKs. */ \
|
||||
template(java_nio_Buffer_klass, java_nio_Buffer, Opt) \
|
||||
@ -164,14 +162,14 @@ class SymbolPropertyTable;
|
||||
template(sun_jkernel_DownloadManager_klass, sun_jkernel_DownloadManager, Opt_Kernel) \
|
||||
\
|
||||
/* Preload boxing klasses */ \
|
||||
template(boolean_klass, java_lang_Boolean, Pre) \
|
||||
template(char_klass, java_lang_Character, Pre) \
|
||||
template(float_klass, java_lang_Float, Pre) \
|
||||
template(double_klass, java_lang_Double, Pre) \
|
||||
template(byte_klass, java_lang_Byte, Pre) \
|
||||
template(short_klass, java_lang_Short, Pre) \
|
||||
template(int_klass, java_lang_Integer, Pre) \
|
||||
template(long_klass, java_lang_Long, Pre) \
|
||||
template(Boolean_klass, java_lang_Boolean, Pre) \
|
||||
template(Character_klass, java_lang_Character, Pre) \
|
||||
template(Float_klass, java_lang_Float, Pre) \
|
||||
template(Double_klass, java_lang_Double, Pre) \
|
||||
template(Byte_klass, java_lang_Byte, Pre) \
|
||||
template(Short_klass, java_lang_Short, Pre) \
|
||||
template(Integer_klass, java_lang_Integer, Pre) \
|
||||
template(Long_klass, java_lang_Long, Pre) \
|
||||
/*end*/
|
||||
|
||||
|
||||
@ -438,8 +436,8 @@ public:
|
||||
// Tells whether ClassLoader.checkPackageAccess is present
|
||||
static bool has_checkPackageAccess() { return _has_checkPackageAccess; }
|
||||
|
||||
static bool class_klass_loaded() { return WK_KLASS(class_klass) != NULL; }
|
||||
static bool cloneable_klass_loaded() { return WK_KLASS(cloneable_klass) != NULL; }
|
||||
static bool Class_klass_loaded() { return WK_KLASS(Class_klass) != NULL; }
|
||||
static bool Cloneable_klass_loaded() { return WK_KLASS(Cloneable_klass) != NULL; }
|
||||
|
||||
// Returns default system loader
|
||||
static oop java_system_loader();
|
||||
|
@ -143,7 +143,7 @@ bool Verifier::verify(instanceKlassHandle klass, Verifier::Mode mode, bool shoul
|
||||
|
||||
bool Verifier::is_eligible_for_verification(instanceKlassHandle klass, bool should_verify_class) {
|
||||
symbolOop name = klass->name();
|
||||
klassOop refl_magic_klass = SystemDictionary::reflect_magic_klass();
|
||||
klassOop refl_magic_klass = SystemDictionary::reflect_MagicAccessorImpl_klass();
|
||||
|
||||
return (should_verify_for(klass->class_loader(), should_verify_class) &&
|
||||
// return if the class is a bootstrapping class
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -70,6 +70,7 @@ static const char* vm_symbol_bodies = VM_SYMBOLS_DO(VM_SYMBOL_BODY, VM_ALIAS_IGN
|
||||
void vmSymbols::initialize(TRAPS) {
|
||||
assert((int)SID_LIMIT <= (1<<log2_SID_LIMIT), "must fit in this bitfield");
|
||||
assert((int)SID_LIMIT*5 > (1<<log2_SID_LIMIT), "make the bitfield smaller, please");
|
||||
assert(vmIntrinsics::FLAG_LIMIT <= (1 << vmIntrinsics::log2_FLAG_LIMIT), "must fit in this bitfield");
|
||||
|
||||
if (!UseSharedSpaces) {
|
||||
const char* string = &vm_symbol_bodies[0];
|
||||
@ -271,6 +272,58 @@ vmSymbols::SID vmSymbols::find_sid(symbolOop symbol) {
|
||||
return sid;
|
||||
}
|
||||
|
||||
static vmIntrinsics::ID wrapper_intrinsic(BasicType type, bool unboxing) {
|
||||
#define TYPE2(type, unboxing) ((int)(type)*2 + ((unboxing) ? 1 : 0))
|
||||
switch (TYPE2(type, unboxing)) {
|
||||
#define BASIC_TYPE_CASE(type, box, unbox) \
|
||||
case TYPE2(type, false): return vmIntrinsics::box; \
|
||||
case TYPE2(type, true): return vmIntrinsics::unbox
|
||||
BASIC_TYPE_CASE(T_BOOLEAN, _Boolean_valueOf, _booleanValue);
|
||||
BASIC_TYPE_CASE(T_BYTE, _Byte_valueOf, _byteValue);
|
||||
BASIC_TYPE_CASE(T_CHAR, _Character_valueOf, _charValue);
|
||||
BASIC_TYPE_CASE(T_SHORT, _Short_valueOf, _shortValue);
|
||||
BASIC_TYPE_CASE(T_INT, _Integer_valueOf, _intValue);
|
||||
BASIC_TYPE_CASE(T_LONG, _Long_valueOf, _longValue);
|
||||
BASIC_TYPE_CASE(T_FLOAT, _Float_valueOf, _floatValue);
|
||||
BASIC_TYPE_CASE(T_DOUBLE, _Double_valueOf, _doubleValue);
|
||||
#undef BASIC_TYPE_CASE
|
||||
}
|
||||
#undef TYPE2
|
||||
return vmIntrinsics::_none;
|
||||
}
|
||||
|
||||
vmIntrinsics::ID vmIntrinsics::for_boxing(BasicType type) {
|
||||
return wrapper_intrinsic(type, false);
|
||||
}
|
||||
vmIntrinsics::ID vmIntrinsics::for_unboxing(BasicType type) {
|
||||
return wrapper_intrinsic(type, true);
|
||||
}
|
||||
|
||||
vmIntrinsics::ID vmIntrinsics::for_raw_conversion(BasicType src, BasicType dest) {
|
||||
#define SRC_DEST(s,d) (((int)(s) << 4) + (int)(d))
|
||||
switch (SRC_DEST(src, dest)) {
|
||||
case SRC_DEST(T_INT, T_FLOAT): return vmIntrinsics::_intBitsToFloat;
|
||||
case SRC_DEST(T_FLOAT, T_INT): return vmIntrinsics::_floatToRawIntBits;
|
||||
|
||||
case SRC_DEST(T_LONG, T_DOUBLE): return vmIntrinsics::_longBitsToDouble;
|
||||
case SRC_DEST(T_DOUBLE, T_LONG): return vmIntrinsics::_doubleToRawLongBits;
|
||||
}
|
||||
#undef SRC_DEST
|
||||
|
||||
return vmIntrinsics::_none;
|
||||
}
|
||||
|
||||
methodOop vmIntrinsics::method_for(vmIntrinsics::ID id) {
|
||||
if (id == _none) return NULL;
|
||||
symbolOop cname = vmSymbols::symbol_at(class_for(id));
|
||||
symbolOop mname = vmSymbols::symbol_at(name_for(id));
|
||||
symbolOop msig = vmSymbols::symbol_at(signature_for(id));
|
||||
if (cname == NULL || mname == NULL || msig == NULL) return NULL;
|
||||
klassOop k = SystemDictionary::find_well_known_klass(cname);
|
||||
if (k == NULL) return NULL;
|
||||
return instanceKlass::cast(k)->find_method(mname, msig);
|
||||
}
|
||||
|
||||
|
||||
#define VM_INTRINSIC_INITIALIZE(id, klass, name, sig, flags) #id "\0"
|
||||
static const char* vm_intrinsic_name_bodies =
|
||||
@ -330,15 +383,15 @@ inline bool match_F_RNY(jshort flags) {
|
||||
}
|
||||
|
||||
// These are for forming case labels:
|
||||
#define ID3(x, y, z) (( jint)(z) + \
|
||||
((jint)(y) << vmSymbols::log2_SID_LIMIT) + \
|
||||
((jint)(x) << (2*vmSymbols::log2_SID_LIMIT)) )
|
||||
#define ID3(x, y, z) (( jlong)(z) + \
|
||||
((jlong)(y) << vmSymbols::log2_SID_LIMIT) + \
|
||||
((jlong)(x) << (2*vmSymbols::log2_SID_LIMIT)) )
|
||||
#define SID_ENUM(n) vmSymbols::VM_SYMBOL_ENUM_NAME(n)
|
||||
|
||||
vmIntrinsics::ID vmIntrinsics::find_id(vmSymbols::SID holder,
|
||||
vmSymbols::SID name,
|
||||
vmSymbols::SID sig,
|
||||
jshort flags) {
|
||||
vmIntrinsics::ID vmIntrinsics::find_id_impl(vmSymbols::SID holder,
|
||||
vmSymbols::SID name,
|
||||
vmSymbols::SID sig,
|
||||
jshort flags) {
|
||||
assert((int)vmSymbols::SID_LIMIT <= (1<<vmSymbols::log2_SID_LIMIT), "must fit");
|
||||
|
||||
// Let the C compiler build the decision tree.
|
||||
@ -383,62 +436,50 @@ const char* vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID id, char* buf,
|
||||
}
|
||||
|
||||
|
||||
// These are for friendly printouts of intrinsics:
|
||||
// These are to get information about intrinsics.
|
||||
|
||||
#define ID4(x, y, z, f) ((ID3(x, y, z) << vmIntrinsics::log2_FLAG_LIMIT) | (jlong) (f))
|
||||
|
||||
static const jlong intrinsic_info_array[vmIntrinsics::ID_LIMIT+1] = {
|
||||
#define VM_INTRINSIC_INFO(ignore_id, klass, name, sig, fcode) \
|
||||
ID4(SID_ENUM(klass), SID_ENUM(name), SID_ENUM(sig), vmIntrinsics::fcode),
|
||||
|
||||
0, VM_INTRINSICS_DO(VM_INTRINSIC_INFO,
|
||||
VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE)
|
||||
0
|
||||
#undef VM_INTRINSIC_INFO
|
||||
};
|
||||
|
||||
inline jlong intrinsic_info(vmIntrinsics::ID id) {
|
||||
return intrinsic_info_array[vmIntrinsics::ID_from((int)id)];
|
||||
}
|
||||
|
||||
vmSymbols::SID vmIntrinsics::class_for(vmIntrinsics::ID id) {
|
||||
#ifndef PRODUCT
|
||||
#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \
|
||||
case id: return SID_ENUM(klass);
|
||||
|
||||
switch (id) {
|
||||
VM_INTRINSICS_DO(VM_INTRINSIC_CASE,
|
||||
VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE);
|
||||
}
|
||||
#undef VM_INTRINSIC_CASE
|
||||
#endif //PRODUCT
|
||||
return vmSymbols::NO_SID;
|
||||
jlong info = intrinsic_info(id);
|
||||
int shift = 2*vmSymbols::log2_SID_LIMIT + log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT);
|
||||
assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1021, "");
|
||||
return vmSymbols::SID( (info >> shift) & mask );
|
||||
}
|
||||
|
||||
vmSymbols::SID vmIntrinsics::name_for(vmIntrinsics::ID id) {
|
||||
#ifndef PRODUCT
|
||||
#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \
|
||||
case id: return SID_ENUM(name);
|
||||
|
||||
switch (id) {
|
||||
VM_INTRINSICS_DO(VM_INTRINSIC_CASE,
|
||||
VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE);
|
||||
}
|
||||
#undef VM_INTRINSIC_CASE
|
||||
#endif //PRODUCT
|
||||
return vmSymbols::NO_SID;
|
||||
jlong info = intrinsic_info(id);
|
||||
int shift = vmSymbols::log2_SID_LIMIT + log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT);
|
||||
assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1022, "");
|
||||
return vmSymbols::SID( (info >> shift) & mask );
|
||||
}
|
||||
|
||||
vmSymbols::SID vmIntrinsics::signature_for(vmIntrinsics::ID id) {
|
||||
#ifndef PRODUCT
|
||||
#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \
|
||||
case id: return SID_ENUM(sig);
|
||||
|
||||
switch (id) {
|
||||
VM_INTRINSICS_DO(VM_INTRINSIC_CASE,
|
||||
VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE);
|
||||
}
|
||||
#undef VM_INTRINSIC_CASE
|
||||
#endif //PRODUCT
|
||||
return vmSymbols::NO_SID;
|
||||
jlong info = intrinsic_info(id);
|
||||
int shift = log2_FLAG_LIMIT, mask = right_n_bits(vmSymbols::log2_SID_LIMIT);
|
||||
assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 1023, "");
|
||||
return vmSymbols::SID( (info >> shift) & mask );
|
||||
}
|
||||
|
||||
vmIntrinsics::Flags vmIntrinsics::flags_for(vmIntrinsics::ID id) {
|
||||
#ifndef PRODUCT
|
||||
#define VM_INTRINSIC_CASE(id, klass, name, sig, fcode) \
|
||||
case id: return fcode;
|
||||
|
||||
switch (id) {
|
||||
VM_INTRINSICS_DO(VM_INTRINSIC_CASE,
|
||||
VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE);
|
||||
}
|
||||
#undef VM_INTRINSIC_CASE
|
||||
#endif //PRODUCT
|
||||
return F_none;
|
||||
jlong info = intrinsic_info(id);
|
||||
int shift = 0, mask = right_n_bits(log2_FLAG_LIMIT);
|
||||
assert(((ID4(1021,1022,1023,15) >> shift) & mask) == 15, "");
|
||||
return Flags( (info >> shift) & mask );
|
||||
}
|
||||
|
||||
|
||||
|
@ -219,7 +219,7 @@
|
||||
template(base_name, "base") \
|
||||
\
|
||||
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
|
||||
template(java_dyn_Dynamic, "java/dyn/Dynamic") \
|
||||
template(java_dyn_InvokeDynamic, "java/dyn/InvokeDynamic") \
|
||||
template(java_dyn_Linkage, "java/dyn/Linkage") \
|
||||
template(java_dyn_CallSite, "java/dyn/CallSite") \
|
||||
template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \
|
||||
@ -347,9 +347,14 @@
|
||||
\
|
||||
/* common signatures names */ \
|
||||
template(void_method_signature, "()V") \
|
||||
template(void_boolean_signature, "()Z") \
|
||||
template(void_byte_signature, "()B") \
|
||||
template(void_char_signature, "()C") \
|
||||
template(void_short_signature, "()S") \
|
||||
template(void_int_signature, "()I") \
|
||||
template(void_long_signature, "()J") \
|
||||
template(void_boolean_signature, "()Z") \
|
||||
template(void_float_signature, "()F") \
|
||||
template(void_double_signature, "()D") \
|
||||
template(int_void_signature, "(I)V") \
|
||||
template(int_int_signature, "(I)I") \
|
||||
template(int_bool_signature, "(I)Z") \
|
||||
@ -854,6 +859,46 @@
|
||||
\
|
||||
do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \
|
||||
/* (symbols invoke_name and invoke_signature defined above) */ \
|
||||
do_intrinsic(_checkSpreadArgument, sun_dyn_MethodHandleImpl, checkSpreadArgument_name, checkSpreadArgument_signature, F_S) \
|
||||
do_name( checkSpreadArgument_name, "checkSpreadArgument") \
|
||||
do_name( checkSpreadArgument_signature, "(Ljava/lang/Object;I)V") \
|
||||
\
|
||||
/* unboxing methods: */ \
|
||||
do_intrinsic(_booleanValue, java_lang_Boolean, booleanValue_name, void_boolean_signature, F_R) \
|
||||
do_name( booleanValue_name, "booleanValue") \
|
||||
do_intrinsic(_byteValue, java_lang_Byte, byteValue_name, void_byte_signature, F_R) \
|
||||
do_name( byteValue_name, "byteValue") \
|
||||
do_intrinsic(_charValue, java_lang_Character, charValue_name, void_char_signature, F_R) \
|
||||
do_name( charValue_name, "charValue") \
|
||||
do_intrinsic(_shortValue, java_lang_Short, shortValue_name, void_short_signature, F_R) \
|
||||
do_name( shortValue_name, "shortValue") \
|
||||
do_intrinsic(_intValue, java_lang_Integer, intValue_name, void_int_signature, F_R) \
|
||||
do_name( intValue_name, "intValue") \
|
||||
do_intrinsic(_longValue, java_lang_Long, longValue_name, void_long_signature, F_R) \
|
||||
do_name( longValue_name, "longValue") \
|
||||
do_intrinsic(_floatValue, java_lang_Float, floatValue_name, void_float_signature, F_R) \
|
||||
do_name( floatValue_name, "floatValue") \
|
||||
do_intrinsic(_doubleValue, java_lang_Double, doubleValue_name, void_double_signature, F_R) \
|
||||
do_name( doubleValue_name, "doubleValue") \
|
||||
\
|
||||
/* boxing methods: */ \
|
||||
do_name( valueOf_name, "valueOf") \
|
||||
do_intrinsic(_Boolean_valueOf, java_lang_Boolean, valueOf_name, Boolean_valueOf_signature, F_S) \
|
||||
do_name( Boolean_valueOf_signature, "(Z)Ljava/lang/Boolean;") \
|
||||
do_intrinsic(_Byte_valueOf, java_lang_Byte, valueOf_name, Byte_valueOf_signature, F_S) \
|
||||
do_name( Byte_valueOf_signature, "(B)Ljava/lang/Byte;") \
|
||||
do_intrinsic(_Character_valueOf, java_lang_Character, valueOf_name, Character_valueOf_signature, F_S) \
|
||||
do_name( Character_valueOf_signature, "(C)Ljava/lang/Character;") \
|
||||
do_intrinsic(_Short_valueOf, java_lang_Short, valueOf_name, Short_valueOf_signature, F_S) \
|
||||
do_name( Short_valueOf_signature, "(S)Ljava/lang/Short;") \
|
||||
do_intrinsic(_Integer_valueOf, java_lang_Integer, valueOf_name, Integer_valueOf_signature, F_S) \
|
||||
do_name( Integer_valueOf_signature, "(I)Ljava/lang/Integer;") \
|
||||
do_intrinsic(_Long_valueOf, java_lang_Long, valueOf_name, Long_valueOf_signature, F_S) \
|
||||
do_name( Long_valueOf_signature, "(J)Ljava/lang/Long;") \
|
||||
do_intrinsic(_Float_valueOf, java_lang_Float, valueOf_name, Float_valueOf_signature, F_S) \
|
||||
do_name( Float_valueOf_signature, "(F)Ljava/lang/Float;") \
|
||||
do_intrinsic(_Double_valueOf, java_lang_Double, valueOf_name, Double_valueOf_signature, F_S) \
|
||||
do_name( Double_valueOf_signature, "(D)Ljava/lang/Double;") \
|
||||
\
|
||||
/*end*/
|
||||
|
||||
@ -984,7 +1029,12 @@ class vmIntrinsics: AllStatic {
|
||||
F_Y, // !static ?native synchronized
|
||||
F_RN, // !static native !synchronized
|
||||
F_SN, // static native !synchronized
|
||||
F_RNY // !static native synchronized
|
||||
F_RNY, // !static native synchronized
|
||||
|
||||
FLAG_LIMIT
|
||||
};
|
||||
enum {
|
||||
log2_FLAG_LIMIT = 4 // checked by an assert at start-up
|
||||
};
|
||||
|
||||
public:
|
||||
@ -996,15 +1046,32 @@ public:
|
||||
|
||||
static const char* name_at(ID id);
|
||||
|
||||
private:
|
||||
static ID find_id_impl(vmSymbols::SID holder,
|
||||
vmSymbols::SID name,
|
||||
vmSymbols::SID sig,
|
||||
jshort flags);
|
||||
|
||||
public:
|
||||
// Given a method's class, name, signature, and access flags, report its ID.
|
||||
static ID find_id(vmSymbols::SID holder,
|
||||
vmSymbols::SID name,
|
||||
vmSymbols::SID sig,
|
||||
jshort flags);
|
||||
jshort flags) {
|
||||
ID id = find_id_impl(holder, name, sig, flags);
|
||||
#ifdef ASSERT
|
||||
// ID _none does not hold the following asserts.
|
||||
if (id == _none) return id;
|
||||
#endif
|
||||
assert( class_for(id) == holder, "correct id");
|
||||
assert( name_for(id) == name, "correct id");
|
||||
assert(signature_for(id) == sig, "correct id");
|
||||
return id;
|
||||
}
|
||||
|
||||
static void verify_method(ID actual_id, methodOop m) PRODUCT_RETURN;
|
||||
|
||||
// No need for these in the product:
|
||||
// Find out the symbols behind an intrinsic:
|
||||
static vmSymbols::SID class_for(ID id);
|
||||
static vmSymbols::SID name_for(ID id);
|
||||
static vmSymbols::SID signature_for(ID id);
|
||||
@ -1014,4 +1081,11 @@ public:
|
||||
|
||||
// Access to intrinsic methods:
|
||||
static methodOop method_for(ID id);
|
||||
|
||||
// Wrapper object methods:
|
||||
static ID for_boxing(BasicType type);
|
||||
static ID for_unboxing(BasicType type);
|
||||
|
||||
// Raw conversion:
|
||||
static ID for_raw_conversion(BasicType src, BasicType dest);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -102,6 +102,9 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
virtual bool is_compiled_by_c2() const { return false; }
|
||||
virtual bool is_compiled_by_c1() const { return false; }
|
||||
|
||||
// Casting
|
||||
nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; }
|
||||
|
||||
// Boundaries
|
||||
address header_begin() const { return (address) this; }
|
||||
address header_end() const { return ((address) this) + _header_size; };
|
||||
@ -201,7 +204,8 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
virtual void print_value_on(outputStream* st) const PRODUCT_RETURN;
|
||||
|
||||
// Print the comment associated with offset on stream, if there is one
|
||||
void print_block_comment(outputStream* stream, intptr_t offset) {
|
||||
virtual void print_block_comment(outputStream* stream, address block_begin) {
|
||||
intptr_t offset = (intptr_t)(block_begin - instructions_begin());
|
||||
_comments.print_block_comment(stream, offset);
|
||||
}
|
||||
|
||||
|
@ -281,6 +281,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset,
|
||||
ciMethod* method,
|
||||
int bci,
|
||||
bool reexecute,
|
||||
bool is_method_handle_invoke,
|
||||
DebugToken* locals,
|
||||
DebugToken* expressions,
|
||||
DebugToken* monitors) {
|
||||
@ -292,8 +293,9 @@ void DebugInformationRecorder::describe_scope(int pc_offset,
|
||||
int stream_offset = stream()->position();
|
||||
last_pd->set_scope_decode_offset(stream_offset);
|
||||
|
||||
// Record reexecute bit into pcDesc
|
||||
// Record flags into pcDesc.
|
||||
last_pd->set_should_reexecute(reexecute);
|
||||
last_pd->set_is_method_handle_invoke(is_method_handle_invoke);
|
||||
|
||||
// serialize sender stream offest
|
||||
stream()->write_int(sender_stream_offset);
|
||||
|
@ -88,6 +88,7 @@ class DebugInformationRecorder: public ResourceObj {
|
||||
ciMethod* method,
|
||||
int bci,
|
||||
bool reexecute,
|
||||
bool is_method_handle_invoke = false,
|
||||
DebugToken* locals = NULL,
|
||||
DebugToken* expressions = NULL,
|
||||
DebugToken* monitors = NULL);
|
||||
|
@ -56,13 +56,13 @@ HS_DTRACE_PROBE_DECL6(hotspot, compiled__method__unload,
|
||||
#endif
|
||||
|
||||
bool nmethod::is_compiled_by_c1() const {
|
||||
if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing
|
||||
if (is_native_method()) return false;
|
||||
assert(compiler() != NULL, "must be");
|
||||
return compiler()->is_c1();
|
||||
}
|
||||
bool nmethod::is_compiled_by_c2() const {
|
||||
if (compiler() == NULL || method() == NULL) return false; // can happen during debug printing
|
||||
if (is_native_method()) return false;
|
||||
assert(compiler() != NULL, "must be");
|
||||
return compiler()->is_c2();
|
||||
}
|
||||
|
||||
@ -1170,7 +1170,7 @@ void nmethod::log_state_change() const {
|
||||
}
|
||||
|
||||
// Common functionality for both make_not_entrant and make_zombie
|
||||
bool nmethod::make_not_entrant_or_zombie(int state) {
|
||||
bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
|
||||
assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
|
||||
|
||||
// If the method is already zombie there is nothing to do
|
||||
@ -1724,9 +1724,9 @@ void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map
|
||||
if (!method()->is_native()) {
|
||||
SimpleScopeDesc ssd(this, fr.pc());
|
||||
Bytecode_invoke* call = Bytecode_invoke_at(ssd.method(), ssd.bci());
|
||||
bool is_static = call->is_invokestatic();
|
||||
bool has_receiver = call->has_receiver();
|
||||
symbolOop signature = call->signature();
|
||||
fr.oops_compiled_arguments_do(signature, is_static, reg_map, f);
|
||||
fr.oops_compiled_arguments_do(signature, has_receiver, reg_map, f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1763,6 +1763,14 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) {
|
||||
"must end with a sentinel");
|
||||
#endif //ASSERT
|
||||
|
||||
// Search for MethodHandle invokes and tag the nmethod.
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (pcs[i].is_method_handle_invoke()) {
|
||||
set_has_method_handle_invokes(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int size = count * sizeof(PcDesc);
|
||||
assert(scopes_pcs_size() >= size, "oob");
|
||||
memcpy(scopes_pcs_begin(), pcs, size);
|
||||
@ -2029,6 +2037,18 @@ bool nmethod::is_deopt_pc(address pc) {
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MethodHandle
|
||||
|
||||
bool nmethod::is_method_handle_return(address return_pc) {
|
||||
if (!has_method_handle_invokes()) return false;
|
||||
PcDesc* pd = pc_desc_at(return_pc);
|
||||
if (pd == NULL)
|
||||
return false;
|
||||
return pd->is_method_handle_invoke();
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Verification
|
||||
|
||||
@ -2379,6 +2399,107 @@ ScopeDesc* nmethod::scope_desc_in(address begin, address end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nmethod::print_nmethod_labels(outputStream* stream, address block_begin) {
|
||||
if (block_begin == entry_point()) stream->print_cr("[Entry Point]");
|
||||
if (block_begin == verified_entry_point()) stream->print_cr("[Verified Entry Point]");
|
||||
if (block_begin == exception_begin()) stream->print_cr("[Exception Handler]");
|
||||
if (block_begin == stub_begin()) stream->print_cr("[Stub Code]");
|
||||
if (block_begin == consts_begin()) stream->print_cr("[Constants]");
|
||||
if (block_begin == entry_point()) {
|
||||
methodHandle m = method();
|
||||
if (m.not_null()) {
|
||||
stream->print(" # ");
|
||||
m->print_value_on(stream);
|
||||
stream->cr();
|
||||
}
|
||||
if (m.not_null() && !is_osr_method()) {
|
||||
ResourceMark rm;
|
||||
int sizeargs = m->size_of_parameters();
|
||||
BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sizeargs);
|
||||
VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, sizeargs);
|
||||
{
|
||||
int sig_index = 0;
|
||||
if (!m->is_static())
|
||||
sig_bt[sig_index++] = T_OBJECT; // 'this'
|
||||
for (SignatureStream ss(m->signature()); !ss.at_return_type(); ss.next()) {
|
||||
BasicType t = ss.type();
|
||||
sig_bt[sig_index++] = t;
|
||||
if (type2size[t] == 2) {
|
||||
sig_bt[sig_index++] = T_VOID;
|
||||
} else {
|
||||
assert(type2size[t] == 1, "size is 1 or 2");
|
||||
}
|
||||
}
|
||||
assert(sig_index == sizeargs, "");
|
||||
}
|
||||
const char* spname = "sp"; // make arch-specific?
|
||||
intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs, false);
|
||||
int stack_slot_offset = this->frame_size() * wordSize;
|
||||
int tab1 = 14, tab2 = 24;
|
||||
int sig_index = 0;
|
||||
int arg_index = (m->is_static() ? 0 : -1);
|
||||
bool did_old_sp = false;
|
||||
for (SignatureStream ss(m->signature()); !ss.at_return_type(); ) {
|
||||
bool at_this = (arg_index == -1);
|
||||
bool at_old_sp = false;
|
||||
BasicType t = (at_this ? T_OBJECT : ss.type());
|
||||
assert(t == sig_bt[sig_index], "sigs in sync");
|
||||
if (at_this)
|
||||
stream->print(" # this: ");
|
||||
else
|
||||
stream->print(" # parm%d: ", arg_index);
|
||||
stream->move_to(tab1);
|
||||
VMReg fst = regs[sig_index].first();
|
||||
VMReg snd = regs[sig_index].second();
|
||||
if (fst->is_reg()) {
|
||||
stream->print("%s", fst->name());
|
||||
if (snd->is_valid()) {
|
||||
stream->print(":%s", snd->name());
|
||||
}
|
||||
} else if (fst->is_stack()) {
|
||||
int offset = fst->reg2stack() * VMRegImpl::stack_slot_size + stack_slot_offset;
|
||||
if (offset == stack_slot_offset) at_old_sp = true;
|
||||
stream->print("[%s+0x%x]", spname, offset);
|
||||
} else {
|
||||
stream->print("reg%d:%d??", (int)(intptr_t)fst, (int)(intptr_t)snd);
|
||||
}
|
||||
stream->print(" ");
|
||||
stream->move_to(tab2);
|
||||
stream->print("= ");
|
||||
if (at_this) {
|
||||
m->method_holder()->print_value_on(stream);
|
||||
} else {
|
||||
bool did_name = false;
|
||||
if (!at_this && ss.is_object()) {
|
||||
symbolOop name = ss.as_symbol_or_null();
|
||||
if (name != NULL) {
|
||||
name->print_value_on(stream);
|
||||
did_name = true;
|
||||
}
|
||||
}
|
||||
if (!did_name)
|
||||
stream->print("%s", type2name(t));
|
||||
}
|
||||
if (at_old_sp) {
|
||||
stream->print(" (%s of caller)", spname);
|
||||
did_old_sp = true;
|
||||
}
|
||||
stream->cr();
|
||||
sig_index += type2size[t];
|
||||
arg_index += 1;
|
||||
if (!at_this) ss.next();
|
||||
}
|
||||
if (!did_old_sp) {
|
||||
stream->print(" # ");
|
||||
stream->move_to(tab1);
|
||||
stream->print("[%s+0x%x]", spname, stack_slot_offset);
|
||||
stream->print(" (%s of caller)", spname);
|
||||
stream->cr();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nmethod::print_code_comment_on(outputStream* st, int column, u_char* begin, u_char* end) {
|
||||
// First, find an oopmap in (begin, end].
|
||||
// We use the odd half-closed interval so that oop maps and scope descs
|
||||
|
@ -81,18 +81,19 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
struct nmFlags {
|
||||
friend class VMStructs;
|
||||
unsigned int version:8; // version number (0 = first version)
|
||||
unsigned int level:4; // optimization level
|
||||
unsigned int age:4; // age (in # of sweep steps)
|
||||
unsigned int version:8; // version number (0 = first version)
|
||||
unsigned int level:4; // optimization level
|
||||
unsigned int age:4; // age (in # of sweep steps)
|
||||
|
||||
unsigned int state:2; // {alive, zombie, unloaded)
|
||||
unsigned int state:2; // {alive, zombie, unloaded)
|
||||
|
||||
unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap?
|
||||
unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures
|
||||
unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies
|
||||
unsigned int markedForReclamation:1; // Used by NMethodSweeper
|
||||
unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap?
|
||||
unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures
|
||||
unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies
|
||||
unsigned int markedForReclamation:1; // Used by NMethodSweeper
|
||||
|
||||
unsigned int has_unsafe_access:1; // May fault due to unsafe access.
|
||||
unsigned int has_unsafe_access:1; // May fault due to unsafe access.
|
||||
unsigned int has_method_handle_invokes:1; // Has this method MethodHandle invokes?
|
||||
|
||||
void clear();
|
||||
};
|
||||
@ -254,7 +255,7 @@ class nmethod : public CodeBlob {
|
||||
const char* reloc_string_for(u_char* begin, u_char* end);
|
||||
// Returns true if this thread changed the state of the nmethod or
|
||||
// false if another thread performed the transition.
|
||||
bool make_not_entrant_or_zombie(int state);
|
||||
bool make_not_entrant_or_zombie(unsigned int state);
|
||||
void inc_decompile_count();
|
||||
|
||||
// used to check that writes to nmFlags are done consistently.
|
||||
@ -409,6 +410,9 @@ class nmethod : public CodeBlob {
|
||||
bool has_unsafe_access() const { return flags.has_unsafe_access; }
|
||||
void set_has_unsafe_access(bool z) { flags.has_unsafe_access = z; }
|
||||
|
||||
bool has_method_handle_invokes() const { return flags.has_method_handle_invokes; }
|
||||
void set_has_method_handle_invokes(bool z) { flags.has_method_handle_invokes = z; }
|
||||
|
||||
int level() const { return flags.level; }
|
||||
void set_level(int newLevel) { check_safepoint(); flags.level = newLevel; }
|
||||
|
||||
@ -541,6 +545,9 @@ class nmethod : public CodeBlob {
|
||||
address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
|
||||
void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
|
||||
|
||||
// MethodHandle
|
||||
bool is_method_handle_return(address return_pc);
|
||||
|
||||
// jvmti support:
|
||||
void post_compiled_method_load_event();
|
||||
|
||||
@ -569,6 +576,13 @@ class nmethod : public CodeBlob {
|
||||
void log_new_nmethod() const;
|
||||
void log_state_change() const;
|
||||
|
||||
// Prints block-level comments, including nmethod specific block labels:
|
||||
virtual void print_block_comment(outputStream* stream, address block_begin) {
|
||||
print_nmethod_labels(stream, block_begin);
|
||||
CodeBlob::print_block_comment(stream, block_begin);
|
||||
}
|
||||
void print_nmethod_labels(outputStream* stream, address block_begin);
|
||||
|
||||
// Prints a comment for one native instruction (reloc info, pc desc)
|
||||
void print_code_comment_on(outputStream* st, int column, address begin, address end);
|
||||
static void print_statistics() PRODUCT_RETURN;
|
||||
|
@ -38,6 +38,7 @@ class PcDesc VALUE_OBJ_CLASS_SPEC {
|
||||
int word;
|
||||
struct {
|
||||
unsigned int reexecute: 1;
|
||||
unsigned int is_method_handle_invoke: 1;
|
||||
} bits;
|
||||
bool operator ==(const PcDescFlags& other) { return word == other.word; }
|
||||
} _flags;
|
||||
@ -72,6 +73,9 @@ class PcDesc VALUE_OBJ_CLASS_SPEC {
|
||||
_flags == pd->_flags;
|
||||
}
|
||||
|
||||
bool is_method_handle_invoke() const { return _flags.bits.is_method_handle_invoke; }
|
||||
void set_is_method_handle_invoke(bool z) { _flags.bits.is_method_handle_invoke = z; }
|
||||
|
||||
// Returns the real pc
|
||||
address real_pc(const nmethod* code) const;
|
||||
|
||||
|
@ -1820,9 +1820,11 @@ void CompileBroker::print_times() {
|
||||
CompileBroker::_t_standard_compilation.seconds(),
|
||||
CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count);
|
||||
tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count);
|
||||
compiler(CompLevel_fast_compile)->print_timers();
|
||||
if (compiler(CompLevel_fast_compile) != compiler(CompLevel_highest_tier)) {
|
||||
compiler(CompLevel_highest_tier)->print_timers();
|
||||
|
||||
if (compiler(CompLevel_fast_compile)) {
|
||||
compiler(CompLevel_fast_compile)->print_timers();
|
||||
if (compiler(CompLevel_fast_compile) != compiler(CompLevel_highest_tier))
|
||||
compiler(CompLevel_highest_tier)->print_timers();
|
||||
}
|
||||
|
||||
tty->cr();
|
||||
|
@ -392,18 +392,18 @@ static const char* patterns[] = {
|
||||
};
|
||||
|
||||
static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) {
|
||||
if (strcmp(name, "*") == 0) return MethodMatcher::Any;
|
||||
|
||||
int match = MethodMatcher::Exact;
|
||||
if (name[0] == '*') {
|
||||
while (name[0] == '*') {
|
||||
match |= MethodMatcher::Suffix;
|
||||
strcpy(name, name + 1);
|
||||
}
|
||||
|
||||
if (strcmp(name, "*") == 0) return MethodMatcher::Any;
|
||||
|
||||
size_t len = strlen(name);
|
||||
if (len > 0 && name[len - 1] == '*') {
|
||||
while (len > 0 && name[len - 1] == '*') {
|
||||
match |= MethodMatcher::Prefix;
|
||||
name[len - 1] = '\0';
|
||||
name[--len] = '\0';
|
||||
}
|
||||
|
||||
if (strstr(name, "*") != NULL) {
|
||||
@ -610,6 +610,14 @@ void compilerOracle_init() {
|
||||
CompilerOracle::parse_from_string(CompileCommand, CompilerOracle::parse_from_line);
|
||||
CompilerOracle::parse_from_string(CompileOnly, CompilerOracle::parse_compile_only);
|
||||
CompilerOracle::parse_from_file();
|
||||
if (lists[PrintCommand] != NULL) {
|
||||
if (PrintAssembly) {
|
||||
warning("CompileCommand and/or .hotspot_compiler file contains 'print' commands, but PrintAssembly is also enabled");
|
||||
} else if (FLAG_IS_DEFAULT(DebugNonSafepoints)) {
|
||||
warning("printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output");
|
||||
DebugNonSafepoints = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -151,8 +151,10 @@ class decode_env {
|
||||
outputStream* st = output();
|
||||
if (_print_bytes && pc > pc0)
|
||||
print_insn_bytes(pc0, pc);
|
||||
if (_nm != NULL)
|
||||
if (_nm != NULL) {
|
||||
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
|
||||
// this calls reloc_string_for which calls oop::print_value_on
|
||||
}
|
||||
|
||||
// Output pc bucket ticks if we have any
|
||||
if (total_ticks() != 0) {
|
||||
@ -273,8 +275,15 @@ void decode_env::print_address(address adr) {
|
||||
oop obj;
|
||||
if (_nm != NULL
|
||||
&& (obj = _nm->embeddedOop_at(cur_insn())) != NULL
|
||||
&& (address) obj == adr) {
|
||||
&& (address) obj == adr
|
||||
&& Universe::heap()->is_in(obj)
|
||||
&& Universe::heap()->is_in(obj->klass())) {
|
||||
julong c = st->count();
|
||||
obj->print_value_on(st);
|
||||
if (st->count() == c) {
|
||||
// No output. (Can happen in product builds.)
|
||||
st->print("(a %s)", Klass::cast(obj->klass())->external_name());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -286,17 +295,9 @@ void decode_env::print_address(address adr) {
|
||||
void decode_env::print_insn_labels() {
|
||||
address p = cur_insn();
|
||||
outputStream* st = output();
|
||||
nmethod* nm = _nm;
|
||||
if (nm != NULL) {
|
||||
if (p == nm->entry_point()) st->print_cr("[Entry Point]");
|
||||
if (p == nm->verified_entry_point()) st->print_cr("[Verified Entry Point]");
|
||||
if (p == nm->exception_begin()) st->print_cr("[Exception Handler]");
|
||||
if (p == nm->stub_begin()) st->print_cr("[Stub Code]");
|
||||
if (p == nm->consts_begin()) st->print_cr("[Constants]");
|
||||
}
|
||||
CodeBlob* cb = _code;
|
||||
if (cb != NULL) {
|
||||
cb->print_block_comment(st, (intptr_t)(p - cb->instructions_begin()));
|
||||
cb->print_block_comment(st, p);
|
||||
}
|
||||
if (_print_pc) {
|
||||
st->print(" " INTPTR_FORMAT ": ", (intptr_t) p);
|
||||
|
@ -782,6 +782,7 @@ void MethodLiveness::BasicBlock::compute_gen_kill_single(ciBytecodeStream *instr
|
||||
case Bytecodes::_invokespecial:
|
||||
case Bytecodes::_invokestatic:
|
||||
case Bytecodes::_invokeinterface:
|
||||
case Bytecodes::_invokedynamic:
|
||||
case Bytecodes::_newarray:
|
||||
case Bytecodes::_anewarray:
|
||||
case Bytecodes::_checkcast:
|
||||
|
@ -62,12 +62,13 @@ TreeList* TreeList::as_TreeList(TreeChunk* tc) {
|
||||
tl->link_head(tc);
|
||||
tl->link_tail(tc);
|
||||
tl->set_count(1);
|
||||
tl->init_statistics();
|
||||
tl->init_statistics(true /* split_birth */);
|
||||
tl->setParent(NULL);
|
||||
tl->setLeft(NULL);
|
||||
tl->setRight(NULL);
|
||||
return tl;
|
||||
}
|
||||
|
||||
TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) {
|
||||
TreeChunk* tc = (TreeChunk*) addr;
|
||||
assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
|
||||
@ -267,6 +268,31 @@ TreeChunk* TreeList::first_available() {
|
||||
return retTC;
|
||||
}
|
||||
|
||||
// Returns the block with the largest heap address amongst
|
||||
// those in the list for this size; potentially slow and expensive,
|
||||
// use with caution!
|
||||
TreeChunk* TreeList::largest_address() {
|
||||
guarantee(head() != NULL, "The head of the list cannot be NULL");
|
||||
FreeChunk* fc = head()->next();
|
||||
TreeChunk* retTC;
|
||||
if (fc == NULL) {
|
||||
retTC = head_as_TreeChunk();
|
||||
} else {
|
||||
// walk down the list and return the one with the highest
|
||||
// heap address among chunks of this size.
|
||||
FreeChunk* last = fc;
|
||||
while (fc->next() != NULL) {
|
||||
if ((HeapWord*)last < (HeapWord*)fc) {
|
||||
last = fc;
|
||||
}
|
||||
fc = fc->next();
|
||||
}
|
||||
retTC = TreeChunk::as_TreeChunk(last);
|
||||
}
|
||||
assert(retTC->list() == this, "Wrong type of chunk.");
|
||||
return retTC;
|
||||
}
|
||||
|
||||
BinaryTreeDictionary::BinaryTreeDictionary(MemRegion mr, bool splay):
|
||||
_splay(splay)
|
||||
{
|
||||
@ -379,7 +405,7 @@ BinaryTreeDictionary::getChunkFromTree(size_t size, Dither dither, bool splay)
|
||||
break;
|
||||
}
|
||||
// The evm code reset the hint of the candidate as
|
||||
// at an interrim point. Why? Seems like this leaves
|
||||
// at an interim point. Why? Seems like this leaves
|
||||
// the hint pointing to a list that didn't work.
|
||||
// curTL->set_hint(hintTL->size());
|
||||
}
|
||||
@ -436,7 +462,7 @@ FreeChunk* BinaryTreeDictionary::findLargestDict() const {
|
||||
TreeList *curTL = root();
|
||||
if (curTL != NULL) {
|
||||
while(curTL->right() != NULL) curTL = curTL->right();
|
||||
return curTL->first_available();
|
||||
return curTL->largest_address();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
@ -664,7 +690,7 @@ void BinaryTreeDictionary::insertChunkInTree(FreeChunk* fc) {
|
||||
}
|
||||
}
|
||||
TreeChunk* tc = TreeChunk::as_TreeChunk(fc);
|
||||
// This chunk is being returned to the binary try. It's embedded
|
||||
// This chunk is being returned to the binary tree. Its embedded
|
||||
// TreeList should be unused at this point.
|
||||
tc->initialize();
|
||||
if (curTL != NULL) { // exact match
|
||||
@ -807,6 +833,8 @@ void BinaryTreeDictionary::dictCensusUpdate(size_t size, bool split, bool birth)
|
||||
}
|
||||
|
||||
bool BinaryTreeDictionary::coalDictOverPopulated(size_t size) {
|
||||
if (FLSAlwaysCoalesceLarge) return true;
|
||||
|
||||
TreeList* list_of_size = findList(size);
|
||||
// None of requested size implies overpopulated.
|
||||
return list_of_size == NULL || list_of_size->coalDesired() <= 0 ||
|
||||
@ -854,17 +882,20 @@ class BeginSweepClosure : public AscendTreeCensusClosure {
|
||||
double _percentage;
|
||||
float _inter_sweep_current;
|
||||
float _inter_sweep_estimate;
|
||||
float _intra_sweep_estimate;
|
||||
|
||||
public:
|
||||
BeginSweepClosure(double p, float inter_sweep_current,
|
||||
float inter_sweep_estimate) :
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) :
|
||||
_percentage(p),
|
||||
_inter_sweep_current(inter_sweep_current),
|
||||
_inter_sweep_estimate(inter_sweep_estimate) { }
|
||||
_inter_sweep_estimate(inter_sweep_estimate),
|
||||
_intra_sweep_estimate(intra_sweep_estimate) { }
|
||||
|
||||
void do_list(FreeList* fl) {
|
||||
double coalSurplusPercent = _percentage;
|
||||
fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate);
|
||||
fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
|
||||
fl->set_coalDesired((ssize_t)((double)fl->desired() * coalSurplusPercent));
|
||||
fl->set_beforeSweep(fl->count());
|
||||
fl->set_bfrSurp(fl->surplus());
|
||||
@ -939,9 +970,10 @@ FreeChunk* BinaryTreeDictionary::find_chunk_ends_at(HeapWord* target) const {
|
||||
}
|
||||
|
||||
void BinaryTreeDictionary::beginSweepDictCensus(double coalSurplusPercent,
|
||||
float inter_sweep_current, float inter_sweep_estimate) {
|
||||
float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
|
||||
BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
|
||||
inter_sweep_estimate);
|
||||
inter_sweep_estimate,
|
||||
intra_sweep_estimate);
|
||||
bsc.do_tree(root());
|
||||
}
|
||||
|
||||
@ -1077,13 +1109,13 @@ void BinaryTreeDictionary::reportStatistics() const {
|
||||
// Print census information - counts, births, deaths, etc.
|
||||
// for each list in the tree. Also print some summary
|
||||
// information.
|
||||
class printTreeCensusClosure : public AscendTreeCensusClosure {
|
||||
class PrintTreeCensusClosure : public AscendTreeCensusClosure {
|
||||
int _print_line;
|
||||
size_t _totalFree;
|
||||
FreeList _total;
|
||||
|
||||
public:
|
||||
printTreeCensusClosure() {
|
||||
PrintTreeCensusClosure() {
|
||||
_print_line = 0;
|
||||
_totalFree = 0;
|
||||
}
|
||||
@ -1113,7 +1145,7 @@ void BinaryTreeDictionary::printDictCensus(void) const {
|
||||
|
||||
gclog_or_tty->print("\nBinaryTree\n");
|
||||
FreeList::print_labels_on(gclog_or_tty, "size");
|
||||
printTreeCensusClosure ptc;
|
||||
PrintTreeCensusClosure ptc;
|
||||
ptc.do_tree(root());
|
||||
|
||||
FreeList* total = ptc.total();
|
||||
@ -1130,6 +1162,38 @@ void BinaryTreeDictionary::printDictCensus(void) const {
|
||||
/(total->desired() != 0 ? (double)total->desired() : 1.0));
|
||||
}
|
||||
|
||||
class PrintFreeListsClosure : public AscendTreeCensusClosure {
|
||||
outputStream* _st;
|
||||
int _print_line;
|
||||
|
||||
public:
|
||||
PrintFreeListsClosure(outputStream* st) {
|
||||
_st = st;
|
||||
_print_line = 0;
|
||||
}
|
||||
void do_list(FreeList* fl) {
|
||||
if (++_print_line >= 40) {
|
||||
FreeList::print_labels_on(_st, "size");
|
||||
_print_line = 0;
|
||||
}
|
||||
fl->print_on(gclog_or_tty);
|
||||
size_t sz = fl->size();
|
||||
for (FreeChunk* fc = fl->head(); fc != NULL;
|
||||
fc = fc->next()) {
|
||||
_st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
|
||||
fc, (HeapWord*)fc + sz,
|
||||
fc->cantCoalesce() ? "\t CC" : "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void BinaryTreeDictionary::print_free_lists(outputStream* st) const {
|
||||
|
||||
FreeList::print_labels_on(st, "size");
|
||||
PrintFreeListsClosure pflc(st);
|
||||
pflc.do_tree(root());
|
||||
}
|
||||
|
||||
// Verify the following tree invariants:
|
||||
// . _root has no parent
|
||||
// . parent and child point to each other
|
||||
|
@ -42,9 +42,6 @@ class TreeList: public FreeList {
|
||||
friend class AscendTreeCensusClosure;
|
||||
friend class DescendTreeCensusClosure;
|
||||
friend class DescendTreeSearchClosure;
|
||||
TreeList* _parent;
|
||||
TreeList* _left;
|
||||
TreeList* _right;
|
||||
|
||||
protected:
|
||||
TreeList* parent() const { return _parent; }
|
||||
@ -82,6 +79,11 @@ class TreeList: public FreeList {
|
||||
// to a TreeChunk.
|
||||
TreeChunk* first_available();
|
||||
|
||||
// Returns the block with the largest heap address amongst
|
||||
// those in the list for this size; potentially slow and expensive,
|
||||
// use with caution!
|
||||
TreeChunk* largest_address();
|
||||
|
||||
// removeChunkReplaceIfNeeded() removes the given "tc" from the TreeList.
|
||||
// If "tc" is the first chunk in the list, it is also the
|
||||
// TreeList that is the node in the tree. removeChunkReplaceIfNeeded()
|
||||
@ -254,8 +256,9 @@ class BinaryTreeDictionary: public FreeBlockDictionary {
|
||||
// Methods called at the beginning of a sweep to prepare the
|
||||
// statistics for the sweep.
|
||||
void beginSweepDictCensus(double coalSurplusPercent,
|
||||
float sweep_current,
|
||||
float sweep_estimate);
|
||||
float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate);
|
||||
// Methods called after the end of a sweep to modify the
|
||||
// statistics for the sweep.
|
||||
void endSweepDictCensus(double splitSurplusPercent);
|
||||
@ -269,6 +272,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary {
|
||||
// Print the statistcis for all the lists in the tree. Also may
|
||||
// print out summaries.
|
||||
void printDictCensus(void) const;
|
||||
void print_free_lists(outputStream* st) const;
|
||||
|
||||
// For debugging. Returns the sum of the _returnedBytes for
|
||||
// all lists in the tree.
|
||||
|
@ -32,7 +32,9 @@
|
||||
// threads. The second argument is in support of an extra locking
|
||||
// check for CFL spaces' free list locks.
|
||||
#ifndef PRODUCT
|
||||
void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
|
||||
void CMSLockVerifier::assert_locked(const Mutex* lock,
|
||||
const Mutex* p_lock1,
|
||||
const Mutex* p_lock2) {
|
||||
if (!Universe::is_fully_initialized()) {
|
||||
return;
|
||||
}
|
||||
@ -40,7 +42,7 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
|
||||
Thread* myThread = Thread::current();
|
||||
|
||||
if (lock == NULL) { // a "lock-free" structure, e.g. MUT, protected by CMS token
|
||||
assert(p_lock == NULL, "Unexpected state");
|
||||
assert(p_lock1 == NULL && p_lock2 == NULL, "Unexpected caller error");
|
||||
if (myThread->is_ConcurrentGC_thread()) {
|
||||
// This test might have to change in the future, if there can be
|
||||
// multiple peer CMS threads. But for now, if we're testing the CMS
|
||||
@ -60,36 +62,39 @@ void CMSLockVerifier::assert_locked(const Mutex* lock, const Mutex* p_lock) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ParallelGCThreads == 0) {
|
||||
if (myThread->is_VM_thread()
|
||||
|| myThread->is_ConcurrentGC_thread()
|
||||
|| myThread->is_Java_thread()) {
|
||||
// Make sure that we are holding the associated lock.
|
||||
assert_lock_strong(lock);
|
||||
} else {
|
||||
if (myThread->is_VM_thread()
|
||||
|| myThread->is_ConcurrentGC_thread()
|
||||
|| myThread->is_Java_thread()) {
|
||||
// Make sure that we are holding the associated lock.
|
||||
assert_lock_strong(lock);
|
||||
// The checking of p_lock is a spl case for CFLS' free list
|
||||
// locks: we make sure that none of the parallel GC work gang
|
||||
// threads are holding "sub-locks" of freeListLock(). We check only
|
||||
// the parDictionaryAllocLock because the others are too numerous.
|
||||
// This spl case code is somewhat ugly and any improvements
|
||||
// are welcome XXX FIX ME!!
|
||||
if (p_lock != NULL) {
|
||||
assert(!p_lock->is_locked() || p_lock->owned_by_self(),
|
||||
"Possible race between this and parallel GC threads");
|
||||
}
|
||||
} else if (myThread->is_GC_task_thread()) {
|
||||
// Make sure that the VM or CMS thread holds lock on our behalf
|
||||
// XXX If there were a concept of a gang_master for a (set of)
|
||||
// gang_workers, we could have used the identity of that thread
|
||||
// for checking ownership here; for now we just disjunct.
|
||||
assert(lock->owner() == VMThread::vm_thread() ||
|
||||
lock->owner() == ConcurrentMarkSweepThread::cmst(),
|
||||
"Should be locked by VM thread or CMS thread on my behalf");
|
||||
} else {
|
||||
// Make sure we didn't miss some obscure corner case
|
||||
ShouldNotReachHere();
|
||||
// The checking of p_lock is a spl case for CFLS' free list
|
||||
// locks: we make sure that none of the parallel GC work gang
|
||||
// threads are holding "sub-locks" of freeListLock(). We check only
|
||||
// the parDictionaryAllocLock because the others are too numerous.
|
||||
// This spl case code is somewhat ugly and any improvements
|
||||
// are welcome.
|
||||
assert(p_lock1 == NULL || !p_lock1->is_locked() || p_lock1->owned_by_self(),
|
||||
"Possible race between this and parallel GC threads");
|
||||
assert(p_lock2 == NULL || !p_lock2->is_locked() || p_lock2->owned_by_self(),
|
||||
"Possible race between this and parallel GC threads");
|
||||
} else if (myThread->is_GC_task_thread()) {
|
||||
// Make sure that the VM or CMS thread holds lock on our behalf
|
||||
// XXX If there were a concept of a gang_master for a (set of)
|
||||
// gang_workers, we could have used the identity of that thread
|
||||
// for checking ownership here; for now we just disjunct.
|
||||
assert(lock->owner() == VMThread::vm_thread() ||
|
||||
lock->owner() == ConcurrentMarkSweepThread::cmst(),
|
||||
"Should be locked by VM thread or CMS thread on my behalf");
|
||||
if (p_lock1 != NULL) {
|
||||
assert_lock_strong(p_lock1);
|
||||
}
|
||||
if (p_lock2 != NULL) {
|
||||
assert_lock_strong(p_lock2);
|
||||
}
|
||||
} else {
|
||||
// Make sure we didn't miss some other thread type calling into here;
|
||||
// perhaps as a result of future VM evolution.
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -29,8 +29,11 @@
|
||||
// the parallel threads.
|
||||
class CMSLockVerifier: AllStatic {
|
||||
public:
|
||||
static void assert_locked(const Mutex* lock, const Mutex* p_lock)
|
||||
static void assert_locked(const Mutex* lock, const Mutex* p_lock1, const Mutex* p_lock2)
|
||||
PRODUCT_RETURN;
|
||||
static void assert_locked(const Mutex* lock, const Mutex* p_lock) {
|
||||
assert_locked(lock, p_lock, NULL);
|
||||
}
|
||||
static void assert_locked(const Mutex* lock) {
|
||||
assert_locked(lock, NULL);
|
||||
}
|
||||
|
@ -62,18 +62,15 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
|
||||
// implementation, namely, the simple binary tree (splaying
|
||||
// temporarily disabled).
|
||||
switch (dictionaryChoice) {
|
||||
case FreeBlockDictionary::dictionaryBinaryTree:
|
||||
_dictionary = new BinaryTreeDictionary(mr);
|
||||
break;
|
||||
case FreeBlockDictionary::dictionarySplayTree:
|
||||
case FreeBlockDictionary::dictionarySkipList:
|
||||
default:
|
||||
warning("dictionaryChoice: selected option not understood; using"
|
||||
" default BinaryTreeDictionary implementation instead.");
|
||||
case FreeBlockDictionary::dictionaryBinaryTree:
|
||||
_dictionary = new BinaryTreeDictionary(mr);
|
||||
break;
|
||||
}
|
||||
splitBirth(mr.word_size());
|
||||
assert(_dictionary != NULL, "CMS dictionary initialization");
|
||||
// The indexed free lists are initially all empty and are lazily
|
||||
// filled in on demand. Initialize the array elements to NULL.
|
||||
@ -388,6 +385,105 @@ size_t CompactibleFreeListSpace::max_alloc_in_words() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st)
|
||||
const {
|
||||
reportIndexedFreeListStatistics();
|
||||
gclog_or_tty->print_cr("Layout of Indexed Freelists");
|
||||
gclog_or_tty->print_cr("---------------------------");
|
||||
FreeList::print_labels_on(st, "size");
|
||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
_indexedFreeList[i].print_on(gclog_or_tty);
|
||||
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
|
||||
fc = fc->next()) {
|
||||
gclog_or_tty->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
|
||||
fc, (HeapWord*)fc + i,
|
||||
fc->cantCoalesce() ? "\t CC" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::print_promo_info_blocks(outputStream* st)
|
||||
const {
|
||||
_promoInfo.print_on(st);
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::print_dictionary_free_lists(outputStream* st)
|
||||
const {
|
||||
_dictionary->reportStatistics();
|
||||
st->print_cr("Layout of Freelists in Tree");
|
||||
st->print_cr("---------------------------");
|
||||
_dictionary->print_free_lists(st);
|
||||
}
|
||||
|
||||
class BlkPrintingClosure: public BlkClosure {
|
||||
const CMSCollector* _collector;
|
||||
const CompactibleFreeListSpace* _sp;
|
||||
const CMSBitMap* _live_bit_map;
|
||||
const bool _post_remark;
|
||||
outputStream* _st;
|
||||
public:
|
||||
BlkPrintingClosure(const CMSCollector* collector,
|
||||
const CompactibleFreeListSpace* sp,
|
||||
const CMSBitMap* live_bit_map,
|
||||
outputStream* st):
|
||||
_collector(collector),
|
||||
_sp(sp),
|
||||
_live_bit_map(live_bit_map),
|
||||
_post_remark(collector->abstract_state() > CMSCollector::FinalMarking),
|
||||
_st(st) { }
|
||||
size_t do_blk(HeapWord* addr);
|
||||
};
|
||||
|
||||
size_t BlkPrintingClosure::do_blk(HeapWord* addr) {
|
||||
size_t sz = _sp->block_size_no_stall(addr, _collector);
|
||||
assert(sz != 0, "Should always be able to compute a size");
|
||||
if (_sp->block_is_obj(addr)) {
|
||||
const bool dead = _post_remark && !_live_bit_map->isMarked(addr);
|
||||
_st->print_cr(PTR_FORMAT ": %s object of size " SIZE_FORMAT "%s",
|
||||
addr,
|
||||
dead ? "dead" : "live",
|
||||
sz,
|
||||
(!dead && CMSPrintObjectsInDump) ? ":" : ".");
|
||||
if (CMSPrintObjectsInDump && !dead) {
|
||||
oop(addr)->print_on(_st);
|
||||
_st->print_cr("--------------------------------------");
|
||||
}
|
||||
} else { // free block
|
||||
_st->print_cr(PTR_FORMAT ": free block of size " SIZE_FORMAT "%s",
|
||||
addr, sz, CMSPrintChunksInDump ? ":" : ".");
|
||||
if (CMSPrintChunksInDump) {
|
||||
((FreeChunk*)addr)->print_on(_st);
|
||||
_st->print_cr("--------------------------------------");
|
||||
}
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::dump_at_safepoint_with_locks(CMSCollector* c,
|
||||
outputStream* st) {
|
||||
st->print_cr("\n=========================");
|
||||
st->print_cr("Block layout in CMS Heap:");
|
||||
st->print_cr("=========================");
|
||||
BlkPrintingClosure bpcl(c, this, c->markBitMap(), st);
|
||||
blk_iterate(&bpcl);
|
||||
|
||||
st->print_cr("\n=======================================");
|
||||
st->print_cr("Order & Layout of Promotion Info Blocks");
|
||||
st->print_cr("=======================================");
|
||||
print_promo_info_blocks(st);
|
||||
|
||||
st->print_cr("\n===========================");
|
||||
st->print_cr("Order of Indexed Free Lists");
|
||||
st->print_cr("=========================");
|
||||
print_indexed_free_lists(st);
|
||||
|
||||
st->print_cr("\n=================================");
|
||||
st->print_cr("Order of Free Lists in Dictionary");
|
||||
st->print_cr("=================================");
|
||||
print_dictionary_free_lists(st);
|
||||
}
|
||||
|
||||
|
||||
void CompactibleFreeListSpace::reportFreeListStatistics() const {
|
||||
assert_lock_strong(&_freelistLock);
|
||||
assert(PrintFLSStatistics != 0, "Reporting error");
|
||||
@ -449,37 +545,37 @@ void CompactibleFreeListSpace::set_end(HeapWord* value) {
|
||||
if (prevEnd != NULL) {
|
||||
// Resize the underlying block offset table.
|
||||
_bt.resize(pointer_delta(value, bottom()));
|
||||
if (value <= prevEnd) {
|
||||
assert(value >= unallocated_block(), "New end is below unallocated block");
|
||||
} else {
|
||||
// Now, take this new chunk and add it to the free blocks.
|
||||
// Note that the BOT has not yet been updated for this block.
|
||||
size_t newFcSize = pointer_delta(value, prevEnd);
|
||||
// XXX This is REALLY UGLY and should be fixed up. XXX
|
||||
if (!_adaptive_freelists && _smallLinearAllocBlock._ptr == NULL) {
|
||||
// Mark the boundary of the new block in BOT
|
||||
_bt.mark_block(prevEnd, value);
|
||||
// put it all in the linAB
|
||||
if (ParallelGCThreads == 0) {
|
||||
_smallLinearAllocBlock._ptr = prevEnd;
|
||||
_smallLinearAllocBlock._word_size = newFcSize;
|
||||
repairLinearAllocBlock(&_smallLinearAllocBlock);
|
||||
} else { // ParallelGCThreads > 0
|
||||
MutexLockerEx x(parDictionaryAllocLock(),
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
_smallLinearAllocBlock._ptr = prevEnd;
|
||||
_smallLinearAllocBlock._word_size = newFcSize;
|
||||
repairLinearAllocBlock(&_smallLinearAllocBlock);
|
||||
}
|
||||
// Births of chunks put into a LinAB are not recorded. Births
|
||||
// of chunks as they are allocated out of a LinAB are.
|
||||
if (value <= prevEnd) {
|
||||
assert(value >= unallocated_block(), "New end is below unallocated block");
|
||||
} else {
|
||||
// Add the block to the free lists, if possible coalescing it
|
||||
// with the last free block, and update the BOT and census data.
|
||||
addChunkToFreeListsAtEndRecordingStats(prevEnd, newFcSize);
|
||||
// Now, take this new chunk and add it to the free blocks.
|
||||
// Note that the BOT has not yet been updated for this block.
|
||||
size_t newFcSize = pointer_delta(value, prevEnd);
|
||||
// XXX This is REALLY UGLY and should be fixed up. XXX
|
||||
if (!_adaptive_freelists && _smallLinearAllocBlock._ptr == NULL) {
|
||||
// Mark the boundary of the new block in BOT
|
||||
_bt.mark_block(prevEnd, value);
|
||||
// put it all in the linAB
|
||||
if (ParallelGCThreads == 0) {
|
||||
_smallLinearAllocBlock._ptr = prevEnd;
|
||||
_smallLinearAllocBlock._word_size = newFcSize;
|
||||
repairLinearAllocBlock(&_smallLinearAllocBlock);
|
||||
} else { // ParallelGCThreads > 0
|
||||
MutexLockerEx x(parDictionaryAllocLock(),
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
_smallLinearAllocBlock._ptr = prevEnd;
|
||||
_smallLinearAllocBlock._word_size = newFcSize;
|
||||
repairLinearAllocBlock(&_smallLinearAllocBlock);
|
||||
}
|
||||
// Births of chunks put into a LinAB are not recorded. Births
|
||||
// of chunks as they are allocated out of a LinAB are.
|
||||
} else {
|
||||
// Add the block to the free lists, if possible coalescing it
|
||||
// with the last free block, and update the BOT and census data.
|
||||
addChunkToFreeListsAtEndRecordingStats(prevEnd, newFcSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FreeListSpace_DCTOC : public Filtering_DCTOC {
|
||||
@ -732,7 +828,7 @@ void CompactibleFreeListSpace::safe_object_iterate(ObjectClosure* blk) {
|
||||
|
||||
void CompactibleFreeListSpace::object_iterate_mem(MemRegion mr,
|
||||
UpwardsObjectClosure* cl) {
|
||||
assert_locked();
|
||||
assert_locked(freelistLock());
|
||||
NOT_PRODUCT(verify_objects_initialized());
|
||||
Space::object_iterate_mem(mr, cl);
|
||||
}
|
||||
@ -1212,12 +1308,15 @@ bool CompactibleFreeListSpace::verifyChunkInFreeLists(FreeChunk* fc) const {
|
||||
void CompactibleFreeListSpace::assert_locked() const {
|
||||
CMSLockVerifier::assert_locked(freelistLock(), parDictionaryAllocLock());
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::assert_locked(const Mutex* lock) const {
|
||||
CMSLockVerifier::assert_locked(lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
FreeChunk* CompactibleFreeListSpace::allocateScratch(size_t size) {
|
||||
// In the parallel case, the main thread holds the free list lock
|
||||
// on behalf the parallel threads.
|
||||
assert_locked();
|
||||
FreeChunk* fc;
|
||||
{
|
||||
// If GC is parallel, this might be called by several threads.
|
||||
@ -1298,17 +1397,18 @@ CompactibleFreeListSpace::getChunkFromLinearAllocBlock(LinearAllocBlock *blk,
|
||||
res = blk->_ptr;
|
||||
_bt.allocated(res, blk->_word_size);
|
||||
} else if (size + MinChunkSize <= blk->_refillSize) {
|
||||
size_t sz = blk->_word_size;
|
||||
// Update _unallocated_block if the size is such that chunk would be
|
||||
// returned to the indexed free list. All other chunks in the indexed
|
||||
// free lists are allocated from the dictionary so that _unallocated_block
|
||||
// has already been adjusted for them. Do it here so that the cost
|
||||
// for all chunks added back to the indexed free lists.
|
||||
if (blk->_word_size < SmallForDictionary) {
|
||||
_bt.allocated(blk->_ptr, blk->_word_size);
|
||||
if (sz < SmallForDictionary) {
|
||||
_bt.allocated(blk->_ptr, sz);
|
||||
}
|
||||
// Return the chunk that isn't big enough, and then refill below.
|
||||
addChunkToFreeLists(blk->_ptr, blk->_word_size);
|
||||
_bt.verify_single_block(blk->_ptr, (blk->_ptr + blk->_word_size));
|
||||
addChunkToFreeLists(blk->_ptr, sz);
|
||||
splitBirth(sz);
|
||||
// Don't keep statistics on adding back chunk from a LinAB.
|
||||
} else {
|
||||
// A refilled block would not satisfy the request.
|
||||
@ -1376,11 +1476,13 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeList(size_t size) {
|
||||
res = getChunkFromIndexedFreeListHelper(size);
|
||||
}
|
||||
_bt.verify_not_unallocated((HeapWord*) res, size);
|
||||
assert(res == NULL || res->size() == size, "Incorrect block size");
|
||||
return res;
|
||||
}
|
||||
|
||||
FreeChunk*
|
||||
CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size) {
|
||||
CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size,
|
||||
bool replenish) {
|
||||
assert_locked();
|
||||
FreeChunk* fc = NULL;
|
||||
if (size < SmallForDictionary) {
|
||||
@ -1398,54 +1500,66 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size) {
|
||||
// and replenishing indexed lists from the small linAB.
|
||||
//
|
||||
FreeChunk* newFc = NULL;
|
||||
size_t replenish_size = CMSIndexedFreeListReplenish * size;
|
||||
const size_t replenish_size = CMSIndexedFreeListReplenish * size;
|
||||
if (replenish_size < SmallForDictionary) {
|
||||
// Do not replenish from an underpopulated size.
|
||||
if (_indexedFreeList[replenish_size].surplus() > 0 &&
|
||||
_indexedFreeList[replenish_size].head() != NULL) {
|
||||
newFc =
|
||||
_indexedFreeList[replenish_size].getChunkAtHead();
|
||||
} else {
|
||||
newFc = _indexedFreeList[replenish_size].getChunkAtHead();
|
||||
} else if (bestFitFirst()) {
|
||||
newFc = bestFitSmall(replenish_size);
|
||||
}
|
||||
}
|
||||
if (newFc != NULL) {
|
||||
splitDeath(replenish_size);
|
||||
} else if (replenish_size > size) {
|
||||
if (newFc == NULL && replenish_size > size) {
|
||||
assert(CMSIndexedFreeListReplenish > 1, "ctl pt invariant");
|
||||
newFc =
|
||||
getChunkFromIndexedFreeListHelper(replenish_size);
|
||||
newFc = getChunkFromIndexedFreeListHelper(replenish_size, false);
|
||||
}
|
||||
// Note: The stats update re split-death of block obtained above
|
||||
// will be recorded below precisely when we know we are going to
|
||||
// be actually splitting it into more than one pieces below.
|
||||
if (newFc != NULL) {
|
||||
assert(newFc->size() == replenish_size, "Got wrong size");
|
||||
size_t i;
|
||||
FreeChunk *curFc, *nextFc;
|
||||
// carve up and link blocks 0, ..., CMSIndexedFreeListReplenish - 2
|
||||
// The last chunk is not added to the lists but is returned as the
|
||||
// free chunk.
|
||||
for (curFc = newFc, nextFc = (FreeChunk*)((HeapWord*)curFc + size),
|
||||
i = 0;
|
||||
i < (CMSIndexedFreeListReplenish - 1);
|
||||
curFc = nextFc, nextFc = (FreeChunk*)((HeapWord*)nextFc + size),
|
||||
i++) {
|
||||
if (replenish || CMSReplenishIntermediate) {
|
||||
// Replenish this list and return one block to caller.
|
||||
size_t i;
|
||||
FreeChunk *curFc, *nextFc;
|
||||
size_t num_blk = newFc->size() / size;
|
||||
assert(num_blk >= 1, "Smaller than requested?");
|
||||
assert(newFc->size() % size == 0, "Should be integral multiple of request");
|
||||
if (num_blk > 1) {
|
||||
// we are sure we will be splitting the block just obtained
|
||||
// into multiple pieces; record the split-death of the original
|
||||
splitDeath(replenish_size);
|
||||
}
|
||||
// carve up and link blocks 0, ..., num_blk - 2
|
||||
// The last chunk is not added to the lists but is returned as the
|
||||
// free chunk.
|
||||
for (curFc = newFc, nextFc = (FreeChunk*)((HeapWord*)curFc + size),
|
||||
i = 0;
|
||||
i < (num_blk - 1);
|
||||
curFc = nextFc, nextFc = (FreeChunk*)((HeapWord*)nextFc + size),
|
||||
i++) {
|
||||
curFc->setSize(size);
|
||||
// Don't record this as a return in order to try and
|
||||
// determine the "returns" from a GC.
|
||||
_bt.verify_not_unallocated((HeapWord*) fc, size);
|
||||
_indexedFreeList[size].returnChunkAtTail(curFc, false);
|
||||
_bt.mark_block((HeapWord*)curFc, size);
|
||||
splitBirth(size);
|
||||
// Don't record the initial population of the indexed list
|
||||
// as a split birth.
|
||||
}
|
||||
|
||||
// check that the arithmetic was OK above
|
||||
assert((HeapWord*)nextFc == (HeapWord*)newFc + num_blk*size,
|
||||
"inconsistency in carving newFc");
|
||||
curFc->setSize(size);
|
||||
// Don't record this as a return in order to try and
|
||||
// determine the "returns" from a GC.
|
||||
_bt.verify_not_unallocated((HeapWord*) fc, size);
|
||||
_indexedFreeList[size].returnChunkAtTail(curFc, false);
|
||||
_bt.mark_block((HeapWord*)curFc, size);
|
||||
splitBirth(size);
|
||||
// Don't record the initial population of the indexed list
|
||||
// as a split birth.
|
||||
fc = curFc;
|
||||
} else {
|
||||
// Return entire block to caller
|
||||
fc = newFc;
|
||||
}
|
||||
|
||||
// check that the arithmetic was OK above
|
||||
assert((HeapWord*)nextFc == (HeapWord*)newFc + replenish_size,
|
||||
"inconsistency in carving newFc");
|
||||
curFc->setSize(size);
|
||||
_bt.mark_block((HeapWord*)curFc, size);
|
||||
splitBirth(size);
|
||||
return curFc;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1453,7 +1567,7 @@ CompactibleFreeListSpace::getChunkFromIndexedFreeListHelper(size_t size) {
|
||||
// replenish the indexed free list.
|
||||
fc = getChunkFromDictionaryExact(size);
|
||||
}
|
||||
assert(fc == NULL || fc->isFree(), "Should be returning a free chunk");
|
||||
// assert(fc == NULL || fc->isFree(), "Should be returning a free chunk");
|
||||
return fc;
|
||||
}
|
||||
|
||||
@ -1512,6 +1626,11 @@ CompactibleFreeListSpace::returnChunkToDictionary(FreeChunk* chunk) {
|
||||
// adjust _unallocated_block downward, as necessary
|
||||
_bt.freed((HeapWord*)chunk, size);
|
||||
_dictionary->returnChunk(chunk);
|
||||
#ifndef PRODUCT
|
||||
if (CMSCollector::abstract_state() != CMSCollector::Sweeping) {
|
||||
TreeChunk::as_TreeChunk(chunk)->list()->verify_stats();
|
||||
}
|
||||
#endif // PRODUCT
|
||||
}
|
||||
|
||||
void
|
||||
@ -1525,6 +1644,11 @@ CompactibleFreeListSpace::returnChunkToFreeList(FreeChunk* fc) {
|
||||
} else {
|
||||
_indexedFreeList[size].returnChunkAtHead(fc);
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
if (CMSCollector::abstract_state() != CMSCollector::Sweeping) {
|
||||
_indexedFreeList[size].verify_stats();
|
||||
}
|
||||
#endif // PRODUCT
|
||||
}
|
||||
|
||||
// Add chunk to end of last block -- if it's the largest
|
||||
@ -1537,7 +1661,6 @@ CompactibleFreeListSpace::addChunkToFreeListsAtEndRecordingStats(
|
||||
HeapWord* chunk, size_t size) {
|
||||
// check that the chunk does lie in this space!
|
||||
assert(chunk != NULL && is_in_reserved(chunk), "Not in this space!");
|
||||
assert_locked();
|
||||
// One of the parallel gc task threads may be here
|
||||
// whilst others are allocating.
|
||||
Mutex* lock = NULL;
|
||||
@ -1991,24 +2114,26 @@ double CompactibleFreeListSpace::flsFrag() const {
|
||||
return frag;
|
||||
}
|
||||
|
||||
#define CoalSurplusPercent 1.05
|
||||
#define SplitSurplusPercent 1.10
|
||||
|
||||
void CompactibleFreeListSpace::beginSweepFLCensus(
|
||||
float inter_sweep_current,
|
||||
float inter_sweep_estimate) {
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) {
|
||||
assert_locked();
|
||||
size_t i;
|
||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
FreeList* fl = &_indexedFreeList[i];
|
||||
fl->compute_desired(inter_sweep_current, inter_sweep_estimate);
|
||||
fl->set_coalDesired((ssize_t)((double)fl->desired() * CoalSurplusPercent));
|
||||
if (PrintFLSStatistics > 1) {
|
||||
gclog_or_tty->print("size[%d] : ", i);
|
||||
}
|
||||
fl->compute_desired(inter_sweep_current, inter_sweep_estimate, intra_sweep_estimate);
|
||||
fl->set_coalDesired((ssize_t)((double)fl->desired() * CMSSmallCoalSurplusPercent));
|
||||
fl->set_beforeSweep(fl->count());
|
||||
fl->set_bfrSurp(fl->surplus());
|
||||
}
|
||||
_dictionary->beginSweepDictCensus(CoalSurplusPercent,
|
||||
_dictionary->beginSweepDictCensus(CMSLargeCoalSurplusPercent,
|
||||
inter_sweep_current,
|
||||
inter_sweep_estimate);
|
||||
inter_sweep_estimate,
|
||||
intra_sweep_estimate);
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::setFLSurplus() {
|
||||
@ -2017,7 +2142,7 @@ void CompactibleFreeListSpace::setFLSurplus() {
|
||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
FreeList *fl = &_indexedFreeList[i];
|
||||
fl->set_surplus(fl->count() -
|
||||
(ssize_t)((double)fl->desired() * SplitSurplusPercent));
|
||||
(ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2048,6 +2173,11 @@ void CompactibleFreeListSpace::clearFLCensus() {
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) {
|
||||
if (PrintFLSStatistics > 0) {
|
||||
HeapWord* largestAddr = (HeapWord*) dictionary()->findLargestDict();
|
||||
gclog_or_tty->print_cr("CMS: Large block " PTR_FORMAT,
|
||||
largestAddr);
|
||||
}
|
||||
setFLSurplus();
|
||||
setFLHints();
|
||||
if (PrintGC && PrintFLSCensus > 0) {
|
||||
@ -2055,7 +2185,7 @@ void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) {
|
||||
}
|
||||
clearFLCensus();
|
||||
assert_locked();
|
||||
_dictionary->endSweepDictCensus(SplitSurplusPercent);
|
||||
_dictionary->endSweepDictCensus(CMSLargeSplitSurplusPercent);
|
||||
}
|
||||
|
||||
bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
|
||||
@ -2312,13 +2442,18 @@ void CompactibleFreeListSpace::verifyIndexedFreeLists() const {
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const {
|
||||
FreeChunk* fc = _indexedFreeList[size].head();
|
||||
FreeChunk* fc = _indexedFreeList[size].head();
|
||||
FreeChunk* tail = _indexedFreeList[size].tail();
|
||||
size_t num = _indexedFreeList[size].count();
|
||||
size_t n = 0;
|
||||
guarantee((size % 2 == 0) || fc == NULL, "Odd slots should be empty");
|
||||
for (; fc != NULL; fc = fc->next()) {
|
||||
for (; fc != NULL; fc = fc->next(), n++) {
|
||||
guarantee(fc->size() == size, "Size inconsistency");
|
||||
guarantee(fc->isFree(), "!free?");
|
||||
guarantee(fc->next() == NULL || fc->next()->prev() == fc, "Broken list");
|
||||
guarantee((fc->next() == NULL) == (fc == tail), "Incorrect tail");
|
||||
}
|
||||
guarantee(n == num, "Incorrect count");
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
@ -2516,11 +2651,41 @@ void PromotionInfo::startTrackingPromotions() {
|
||||
_tracking = true;
|
||||
}
|
||||
|
||||
void PromotionInfo::stopTrackingPromotions() {
|
||||
#define CMSPrintPromoBlockInfo 1
|
||||
|
||||
void PromotionInfo::stopTrackingPromotions(uint worker_id) {
|
||||
assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex,
|
||||
"spooling inconsistency?");
|
||||
_firstIndex = _nextIndex = 1;
|
||||
_tracking = false;
|
||||
if (CMSPrintPromoBlockInfo > 1) {
|
||||
print_statistics(worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
void PromotionInfo::print_statistics(uint worker_id) const {
|
||||
assert(_spoolHead == _spoolTail && _firstIndex == _nextIndex,
|
||||
"Else will undercount");
|
||||
assert(CMSPrintPromoBlockInfo > 0, "Else unnecessary call");
|
||||
// Count the number of blocks and slots in the free pool
|
||||
size_t slots = 0;
|
||||
size_t blocks = 0;
|
||||
for (SpoolBlock* cur_spool = _spareSpool;
|
||||
cur_spool != NULL;
|
||||
cur_spool = cur_spool->nextSpoolBlock) {
|
||||
// the first entry is just a self-pointer; indices 1 through
|
||||
// bufferSize - 1 are occupied (thus, bufferSize - 1 slots).
|
||||
guarantee((void*)cur_spool->displacedHdr == (void*)&cur_spool->displacedHdr,
|
||||
"first entry of displacedHdr should be self-referential");
|
||||
slots += cur_spool->bufferSize - 1;
|
||||
blocks++;
|
||||
}
|
||||
if (_spoolHead != NULL) {
|
||||
slots += _spoolHead->bufferSize - 1;
|
||||
blocks++;
|
||||
}
|
||||
gclog_or_tty->print_cr(" [worker %d] promo_blocks = %d, promo_slots = %d ",
|
||||
worker_id, blocks, slots);
|
||||
}
|
||||
|
||||
// When _spoolTail is not NULL, then the slot <_spoolTail, _nextIndex>
|
||||
@ -2584,15 +2749,84 @@ void PromotionInfo::verify() const {
|
||||
guarantee(numDisplacedHdrs == numObjsWithDisplacedHdrs, "Displaced hdr count");
|
||||
}
|
||||
|
||||
void PromotionInfo::print_on(outputStream* st) const {
|
||||
SpoolBlock* curSpool = NULL;
|
||||
size_t i = 0;
|
||||
st->print_cr("start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")",
|
||||
_firstIndex, _nextIndex);
|
||||
for (curSpool = _spoolHead; curSpool != _spoolTail && curSpool != NULL;
|
||||
curSpool = curSpool->nextSpoolBlock) {
|
||||
curSpool->print_on(st);
|
||||
st->print_cr(" active ");
|
||||
i++;
|
||||
}
|
||||
for (curSpool = _spoolTail; curSpool != NULL;
|
||||
curSpool = curSpool->nextSpoolBlock) {
|
||||
curSpool->print_on(st);
|
||||
st->print_cr(" inactive ");
|
||||
i++;
|
||||
}
|
||||
for (curSpool = _spareSpool; curSpool != NULL;
|
||||
curSpool = curSpool->nextSpoolBlock) {
|
||||
curSpool->print_on(st);
|
||||
st->print_cr(" free ");
|
||||
i++;
|
||||
}
|
||||
st->print_cr(SIZE_FORMAT " header spooling blocks", i);
|
||||
}
|
||||
|
||||
void SpoolBlock::print_on(outputStream* st) const {
|
||||
st->print("[" PTR_FORMAT "," PTR_FORMAT "), " SIZE_FORMAT " HeapWords -> " PTR_FORMAT,
|
||||
this, (HeapWord*)displacedHdr + bufferSize,
|
||||
bufferSize, nextSpoolBlock);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CFLS_LAB
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define VECTOR_257(x) \
|
||||
/* 1 2 3 4 5 6 7 8 9 1x 11 12 13 14 15 16 17 18 19 2x 21 22 23 24 25 26 27 28 29 3x 31 32 */ \
|
||||
{ x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, \
|
||||
x }
|
||||
|
||||
// Initialize with default setting of CMSParPromoteBlocksToClaim, _not_
|
||||
// OldPLABSize, whose static default is different; if overridden at the
|
||||
// command-line, this will get reinitialized via a call to
|
||||
// modify_initialization() below.
|
||||
AdaptiveWeightedAverage CFLS_LAB::_blocks_to_claim[] =
|
||||
VECTOR_257(AdaptiveWeightedAverage(OldPLABWeight, (float)CMSParPromoteBlocksToClaim));
|
||||
size_t CFLS_LAB::_global_num_blocks[] = VECTOR_257(0);
|
||||
int CFLS_LAB::_global_num_workers[] = VECTOR_257(0);
|
||||
|
||||
CFLS_LAB::CFLS_LAB(CompactibleFreeListSpace* cfls) :
|
||||
_cfls(cfls)
|
||||
{
|
||||
_blocks_to_claim = CMSParPromoteBlocksToClaim;
|
||||
assert(CompactibleFreeListSpace::IndexSetSize == 257, "Modify VECTOR_257() macro above");
|
||||
for (size_t i = CompactibleFreeListSpace::IndexSetStart;
|
||||
i < CompactibleFreeListSpace::IndexSetSize;
|
||||
i += CompactibleFreeListSpace::IndexSetStride) {
|
||||
_indexedFreeList[i].set_size(i);
|
||||
_num_blocks[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool _CFLS_LAB_modified = false;
|
||||
|
||||
void CFLS_LAB::modify_initialization(size_t n, unsigned wt) {
|
||||
assert(!_CFLS_LAB_modified, "Call only once");
|
||||
_CFLS_LAB_modified = true;
|
||||
for (size_t i = CompactibleFreeListSpace::IndexSetStart;
|
||||
i < CompactibleFreeListSpace::IndexSetSize;
|
||||
i += CompactibleFreeListSpace::IndexSetStride) {
|
||||
_blocks_to_claim[i].modify(n, wt, true /* force */);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2607,11 +2841,9 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) {
|
||||
if (res == NULL) return NULL;
|
||||
} else {
|
||||
FreeList* fl = &_indexedFreeList[word_sz];
|
||||
bool filled = false; //TRAP
|
||||
if (fl->count() == 0) {
|
||||
bool filled = true; //TRAP
|
||||
// Attempt to refill this local free list.
|
||||
_cfls->par_get_chunk_of_blocks(word_sz, _blocks_to_claim, fl);
|
||||
get_from_global_pool(word_sz, fl);
|
||||
// If it didn't work, give up.
|
||||
if (fl->count() == 0) return NULL;
|
||||
}
|
||||
@ -2626,80 +2858,190 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) {
|
||||
return (HeapWord*)res;
|
||||
}
|
||||
|
||||
void CFLS_LAB::retire() {
|
||||
for (size_t i = CompactibleFreeListSpace::IndexSetStart;
|
||||
// Get a chunk of blocks of the right size and update related
|
||||
// book-keeping stats
|
||||
void CFLS_LAB::get_from_global_pool(size_t word_sz, FreeList* fl) {
|
||||
// Get the #blocks we want to claim
|
||||
size_t n_blks = (size_t)_blocks_to_claim[word_sz].average();
|
||||
assert(n_blks > 0, "Error");
|
||||
assert(ResizePLAB || n_blks == OldPLABSize, "Error");
|
||||
// In some cases, when the application has a phase change,
|
||||
// there may be a sudden and sharp shift in the object survival
|
||||
// profile, and updating the counts at the end of a scavenge
|
||||
// may not be quick enough, giving rise to large scavenge pauses
|
||||
// during these phase changes. It is beneficial to detect such
|
||||
// changes on-the-fly during a scavenge and avoid such a phase-change
|
||||
// pothole. The following code is a heuristic attempt to do that.
|
||||
// It is protected by a product flag until we have gained
|
||||
// enough experience with this heuristic and fine-tuned its behaviour.
|
||||
// WARNING: This might increase fragmentation if we overreact to
|
||||
// small spikes, so some kind of historical smoothing based on
|
||||
// previous experience with the greater reactivity might be useful.
|
||||
// Lacking sufficient experience, CMSOldPLABResizeQuicker is disabled by
|
||||
// default.
|
||||
if (ResizeOldPLAB && CMSOldPLABResizeQuicker) {
|
||||
size_t multiple = _num_blocks[word_sz]/(CMSOldPLABToleranceFactor*CMSOldPLABNumRefills*n_blks);
|
||||
n_blks += CMSOldPLABReactivityFactor*multiple*n_blks;
|
||||
n_blks = MIN2(n_blks, CMSOldPLABMax);
|
||||
}
|
||||
assert(n_blks > 0, "Error");
|
||||
_cfls->par_get_chunk_of_blocks(word_sz, n_blks, fl);
|
||||
// Update stats table entry for this block size
|
||||
_num_blocks[word_sz] += fl->count();
|
||||
}
|
||||
|
||||
void CFLS_LAB::compute_desired_plab_size() {
|
||||
for (size_t i = CompactibleFreeListSpace::IndexSetStart;
|
||||
i < CompactibleFreeListSpace::IndexSetSize;
|
||||
i += CompactibleFreeListSpace::IndexSetStride) {
|
||||
if (_indexedFreeList[i].count() > 0) {
|
||||
MutexLockerEx x(_cfls->_indexedFreeListParLocks[i],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
_cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]);
|
||||
// Reset this list.
|
||||
_indexedFreeList[i] = FreeList();
|
||||
_indexedFreeList[i].set_size(i);
|
||||
assert((_global_num_workers[i] == 0) == (_global_num_blocks[i] == 0),
|
||||
"Counter inconsistency");
|
||||
if (_global_num_workers[i] > 0) {
|
||||
// Need to smooth wrt historical average
|
||||
if (ResizeOldPLAB) {
|
||||
_blocks_to_claim[i].sample(
|
||||
MAX2((size_t)CMSOldPLABMin,
|
||||
MIN2((size_t)CMSOldPLABMax,
|
||||
_global_num_blocks[i]/(_global_num_workers[i]*CMSOldPLABNumRefills))));
|
||||
}
|
||||
// Reset counters for next round
|
||||
_global_num_workers[i] = 0;
|
||||
_global_num_blocks[i] = 0;
|
||||
if (PrintOldPLAB) {
|
||||
gclog_or_tty->print_cr("[%d]: %d", i, (size_t)_blocks_to_claim[i].average());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompactibleFreeListSpace::
|
||||
par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) {
|
||||
void CFLS_LAB::retire(int tid) {
|
||||
// We run this single threaded with the world stopped;
|
||||
// so no need for locks and such.
|
||||
#define CFLS_LAB_PARALLEL_ACCESS 0
|
||||
NOT_PRODUCT(Thread* t = Thread::current();)
|
||||
assert(Thread::current()->is_VM_thread(), "Error");
|
||||
assert(CompactibleFreeListSpace::IndexSetStart == CompactibleFreeListSpace::IndexSetStride,
|
||||
"Will access to uninitialized slot below");
|
||||
#if CFLS_LAB_PARALLEL_ACCESS
|
||||
for (size_t i = CompactibleFreeListSpace::IndexSetSize - 1;
|
||||
i > 0;
|
||||
i -= CompactibleFreeListSpace::IndexSetStride) {
|
||||
#else // CFLS_LAB_PARALLEL_ACCESS
|
||||
for (size_t i = CompactibleFreeListSpace::IndexSetStart;
|
||||
i < CompactibleFreeListSpace::IndexSetSize;
|
||||
i += CompactibleFreeListSpace::IndexSetStride) {
|
||||
#endif // !CFLS_LAB_PARALLEL_ACCESS
|
||||
assert(_num_blocks[i] >= (size_t)_indexedFreeList[i].count(),
|
||||
"Can't retire more than what we obtained");
|
||||
if (_num_blocks[i] > 0) {
|
||||
size_t num_retire = _indexedFreeList[i].count();
|
||||
assert(_num_blocks[i] > num_retire, "Should have used at least one");
|
||||
{
|
||||
#if CFLS_LAB_PARALLEL_ACCESS
|
||||
MutexLockerEx x(_cfls->_indexedFreeListParLocks[i],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
#endif // CFLS_LAB_PARALLEL_ACCESS
|
||||
// Update globals stats for num_blocks used
|
||||
_global_num_blocks[i] += (_num_blocks[i] - num_retire);
|
||||
_global_num_workers[i]++;
|
||||
assert(_global_num_workers[i] <= (ssize_t)ParallelGCThreads, "Too big");
|
||||
if (num_retire > 0) {
|
||||
_cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]);
|
||||
// Reset this list.
|
||||
_indexedFreeList[i] = FreeList();
|
||||
_indexedFreeList[i].set_size(i);
|
||||
}
|
||||
}
|
||||
if (PrintOldPLAB) {
|
||||
gclog_or_tty->print_cr("%d[%d]: %d/%d/%d",
|
||||
tid, i, num_retire, _num_blocks[i], (size_t)_blocks_to_claim[i].average());
|
||||
}
|
||||
// Reset stats for next round
|
||||
_num_blocks[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) {
|
||||
assert(fl->count() == 0, "Precondition.");
|
||||
assert(word_sz < CompactibleFreeListSpace::IndexSetSize,
|
||||
"Precondition");
|
||||
|
||||
// We'll try all multiples of word_sz in the indexed set (starting with
|
||||
// word_sz itself), then try getting a big chunk and splitting it.
|
||||
int k = 1;
|
||||
size_t cur_sz = k * word_sz;
|
||||
bool found = false;
|
||||
while (cur_sz < CompactibleFreeListSpace::IndexSetSize && k == 1) {
|
||||
FreeList* gfl = &_indexedFreeList[cur_sz];
|
||||
FreeList fl_for_cur_sz; // Empty.
|
||||
fl_for_cur_sz.set_size(cur_sz);
|
||||
{
|
||||
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
if (gfl->count() != 0) {
|
||||
size_t nn = MAX2(n/k, (size_t)1);
|
||||
gfl->getFirstNChunksFromList(nn, &fl_for_cur_sz);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
// Now transfer fl_for_cur_sz to fl. Common case, we hope, is k = 1.
|
||||
if (found) {
|
||||
if (k == 1) {
|
||||
fl->prepend(&fl_for_cur_sz);
|
||||
} else {
|
||||
// Divide each block on fl_for_cur_sz up k ways.
|
||||
FreeChunk* fc;
|
||||
while ((fc = fl_for_cur_sz.getChunkAtHead()) != NULL) {
|
||||
// Must do this in reverse order, so that anybody attempting to
|
||||
// access the main chunk sees it as a single free block until we
|
||||
// change it.
|
||||
size_t fc_size = fc->size();
|
||||
for (int i = k-1; i >= 0; i--) {
|
||||
FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz);
|
||||
ffc->setSize(word_sz);
|
||||
ffc->linkNext(NULL);
|
||||
ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
|
||||
// Above must occur before BOT is updated below.
|
||||
// splitting from the right, fc_size == (k - i + 1) * wordsize
|
||||
_bt.mark_block((HeapWord*)ffc, word_sz);
|
||||
fc_size -= word_sz;
|
||||
_bt.verify_not_unallocated((HeapWord*)ffc, ffc->size());
|
||||
_bt.verify_single_block((HeapWord*)fc, fc_size);
|
||||
_bt.verify_single_block((HeapWord*)ffc, ffc->size());
|
||||
// Push this on "fl".
|
||||
fl->returnChunkAtHead(ffc);
|
||||
// We'll try all multiples of word_sz in the indexed set, starting with
|
||||
// word_sz itself and, if CMSSplitIndexedFreeListBlocks, try larger multiples,
|
||||
// then try getting a big chunk and splitting it.
|
||||
{
|
||||
bool found;
|
||||
int k;
|
||||
size_t cur_sz;
|
||||
for (k = 1, cur_sz = k * word_sz, found = false;
|
||||
(cur_sz < CompactibleFreeListSpace::IndexSetSize) &&
|
||||
(CMSSplitIndexedFreeListBlocks || k <= 1);
|
||||
k++, cur_sz = k * word_sz) {
|
||||
FreeList* gfl = &_indexedFreeList[cur_sz];
|
||||
FreeList fl_for_cur_sz; // Empty.
|
||||
fl_for_cur_sz.set_size(cur_sz);
|
||||
{
|
||||
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
if (gfl->count() != 0) {
|
||||
// nn is the number of chunks of size cur_sz that
|
||||
// we'd need to split k-ways each, in order to create
|
||||
// "n" chunks of size word_sz each.
|
||||
const size_t nn = MAX2(n/k, (size_t)1);
|
||||
gfl->getFirstNChunksFromList(nn, &fl_for_cur_sz);
|
||||
found = true;
|
||||
if (k > 1) {
|
||||
// Update split death stats for the cur_sz-size blocks list:
|
||||
// we increment the split death count by the number of blocks
|
||||
// we just took from the cur_sz-size blocks list and which
|
||||
// we will be splitting below.
|
||||
ssize_t deaths = _indexedFreeList[cur_sz].splitDeaths() +
|
||||
fl_for_cur_sz.count();
|
||||
_indexedFreeList[cur_sz].set_splitDeaths(deaths);
|
||||
}
|
||||
// TRAP
|
||||
assert(fl->tail()->next() == NULL, "List invariant.");
|
||||
}
|
||||
}
|
||||
return;
|
||||
// Now transfer fl_for_cur_sz to fl. Common case, we hope, is k = 1.
|
||||
if (found) {
|
||||
if (k == 1) {
|
||||
fl->prepend(&fl_for_cur_sz);
|
||||
} else {
|
||||
// Divide each block on fl_for_cur_sz up k ways.
|
||||
FreeChunk* fc;
|
||||
while ((fc = fl_for_cur_sz.getChunkAtHead()) != NULL) {
|
||||
// Must do this in reverse order, so that anybody attempting to
|
||||
// access the main chunk sees it as a single free block until we
|
||||
// change it.
|
||||
size_t fc_size = fc->size();
|
||||
for (int i = k-1; i >= 0; i--) {
|
||||
FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz);
|
||||
ffc->setSize(word_sz);
|
||||
ffc->linkNext(NULL);
|
||||
ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
|
||||
// Above must occur before BOT is updated below.
|
||||
// splitting from the right, fc_size == (k - i + 1) * wordsize
|
||||
_bt.mark_block((HeapWord*)ffc, word_sz);
|
||||
fc_size -= word_sz;
|
||||
_bt.verify_not_unallocated((HeapWord*)ffc, ffc->size());
|
||||
_bt.verify_single_block((HeapWord*)fc, fc_size);
|
||||
_bt.verify_single_block((HeapWord*)ffc, ffc->size());
|
||||
// Push this on "fl".
|
||||
fl->returnChunkAtHead(ffc);
|
||||
}
|
||||
// TRAP
|
||||
assert(fl->tail()->next() == NULL, "List invariant.");
|
||||
}
|
||||
}
|
||||
// Update birth stats for this block size.
|
||||
size_t num = fl->count();
|
||||
MutexLockerEx x(_indexedFreeListParLocks[word_sz],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
ssize_t births = _indexedFreeList[word_sz].splitBirths() + num;
|
||||
_indexedFreeList[word_sz].set_splitBirths(births);
|
||||
return;
|
||||
}
|
||||
}
|
||||
k++; cur_sz = k * word_sz;
|
||||
}
|
||||
// Otherwise, we'll split a block from the dictionary.
|
||||
FreeChunk* fc = NULL;
|
||||
@ -2723,17 +3065,31 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) {
|
||||
}
|
||||
}
|
||||
if (fc == NULL) return;
|
||||
assert((ssize_t)n >= 1, "Control point invariant");
|
||||
// Otherwise, split up that block.
|
||||
size_t nn = fc->size() / word_sz;
|
||||
const size_t nn = fc->size() / word_sz;
|
||||
n = MIN2(nn, n);
|
||||
assert((ssize_t)n >= 1, "Control point invariant");
|
||||
rem = fc->size() - n * word_sz;
|
||||
// If there is a remainder, and it's too small, allocate one fewer.
|
||||
if (rem > 0 && rem < MinChunkSize) {
|
||||
n--; rem += word_sz;
|
||||
}
|
||||
// Note that at this point we may have n == 0.
|
||||
assert((ssize_t)n >= 0, "Control point invariant");
|
||||
|
||||
// If n is 0, the chunk fc that was found is not large
|
||||
// enough to leave a viable remainder. We are unable to
|
||||
// allocate even one block. Return fc to the
|
||||
// dictionary and return, leaving "fl" empty.
|
||||
if (n == 0) {
|
||||
returnChunkToDictionary(fc);
|
||||
return;
|
||||
}
|
||||
|
||||
// First return the remainder, if any.
|
||||
// Note that we hold the lock until we decide if we're going to give
|
||||
// back the remainder to the dictionary, since a contending allocator
|
||||
// back the remainder to the dictionary, since a concurrent allocation
|
||||
// may otherwise see the heap as empty. (We're willing to take that
|
||||
// hit if the block is a small block.)
|
||||
if (rem > 0) {
|
||||
@ -2743,18 +3099,16 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) {
|
||||
rem_fc->linkNext(NULL);
|
||||
rem_fc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
|
||||
// Above must occur before BOT is updated below.
|
||||
assert((ssize_t)n > 0 && prefix_size > 0 && rem_fc > fc, "Error");
|
||||
_bt.split_block((HeapWord*)fc, fc->size(), prefix_size);
|
||||
if (rem >= IndexSetSize) {
|
||||
returnChunkToDictionary(rem_fc);
|
||||
dictionary()->dictCensusUpdate(fc->size(),
|
||||
true /*split*/,
|
||||
true /*birth*/);
|
||||
dictionary()->dictCensusUpdate(rem, true /*split*/, true /*birth*/);
|
||||
rem_fc = NULL;
|
||||
}
|
||||
// Otherwise, return it to the small list below.
|
||||
}
|
||||
}
|
||||
//
|
||||
if (rem_fc != NULL) {
|
||||
MutexLockerEx x(_indexedFreeListParLocks[rem],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
@ -2762,7 +3116,7 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) {
|
||||
_indexedFreeList[rem].returnChunkAtHead(rem_fc);
|
||||
smallSplitBirth(rem);
|
||||
}
|
||||
|
||||
assert((ssize_t)n > 0 && fc != NULL, "Consistency");
|
||||
// Now do the splitting up.
|
||||
// Must do this in reverse order, so that anybody attempting to
|
||||
// access the main chunk sees it as a single free block until we
|
||||
@ -2792,13 +3146,15 @@ par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList* fl) {
|
||||
_bt.verify_single_block((HeapWord*)fc, fc->size());
|
||||
fl->returnChunkAtHead(fc);
|
||||
|
||||
assert((ssize_t)n > 0 && (ssize_t)n == fl->count(), "Incorrect number of blocks");
|
||||
{
|
||||
// Update the stats for this block size.
|
||||
MutexLockerEx x(_indexedFreeListParLocks[word_sz],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
ssize_t new_births = _indexedFreeList[word_sz].splitBirths() + n;
|
||||
_indexedFreeList[word_sz].set_splitBirths(new_births);
|
||||
ssize_t new_surplus = _indexedFreeList[word_sz].surplus() + n;
|
||||
_indexedFreeList[word_sz].set_surplus(new_surplus);
|
||||
const ssize_t births = _indexedFreeList[word_sz].splitBirths() + n;
|
||||
_indexedFreeList[word_sz].set_splitBirths(births);
|
||||
// ssize_t new_surplus = _indexedFreeList[word_sz].surplus() + n;
|
||||
// _indexedFreeList[word_sz].set_surplus(new_surplus);
|
||||
}
|
||||
|
||||
// TRAP
|
||||
|
@ -25,8 +25,6 @@
|
||||
// Classes in support of keeping track of promotions into a non-Contiguous
|
||||
// space, in this case a CompactibleFreeListSpace.
|
||||
|
||||
#define CFLS_LAB_REFILL_STATS 0
|
||||
|
||||
// Forward declarations
|
||||
class CompactibleFreeListSpace;
|
||||
class BlkClosure;
|
||||
@ -89,6 +87,9 @@ class SpoolBlock: public FreeChunk {
|
||||
displacedHdr = (markOop*)&displacedHdr;
|
||||
nextSpoolBlock = NULL;
|
||||
}
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void print() const { print_on(gclog_or_tty); }
|
||||
};
|
||||
|
||||
class PromotionInfo VALUE_OBJ_CLASS_SPEC {
|
||||
@ -121,7 +122,7 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC {
|
||||
return _promoHead == NULL;
|
||||
}
|
||||
void startTrackingPromotions();
|
||||
void stopTrackingPromotions();
|
||||
void stopTrackingPromotions(uint worker_id = 0);
|
||||
bool tracking() const { return _tracking; }
|
||||
void track(PromotedObject* trackOop); // keep track of a promoted oop
|
||||
// The following variant must be used when trackOop is not fully
|
||||
@ -161,6 +162,9 @@ class PromotionInfo VALUE_OBJ_CLASS_SPEC {
|
||||
_nextIndex = 0;
|
||||
|
||||
}
|
||||
|
||||
void print_on(outputStream* st) const;
|
||||
void print_statistics(uint worker_id) const;
|
||||
};
|
||||
|
||||
class LinearAllocBlock VALUE_OBJ_CLASS_SPEC {
|
||||
@ -243,6 +247,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
mutable Mutex _freelistLock;
|
||||
// locking verifier convenience function
|
||||
void assert_locked() const PRODUCT_RETURN;
|
||||
void assert_locked(const Mutex* lock) const PRODUCT_RETURN;
|
||||
|
||||
// Linear allocation blocks
|
||||
LinearAllocBlock _smallLinearAllocBlock;
|
||||
@ -281,13 +286,6 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
// Locks protecting the exact lists during par promotion allocation.
|
||||
Mutex* _indexedFreeListParLocks[IndexSetSize];
|
||||
|
||||
#if CFLS_LAB_REFILL_STATS
|
||||
// Some statistics.
|
||||
jint _par_get_chunk_from_small;
|
||||
jint _par_get_chunk_from_large;
|
||||
#endif
|
||||
|
||||
|
||||
// Attempt to obtain up to "n" blocks of the size "word_sz" (which is
|
||||
// required to be smaller than "IndexSetSize".) If successful,
|
||||
// adds them to "fl", which is required to be an empty free list.
|
||||
@ -320,7 +318,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
// Helper function for getChunkFromIndexedFreeList.
|
||||
// Replenish the indexed free list for this "size". Do not take from an
|
||||
// underpopulated size.
|
||||
FreeChunk* getChunkFromIndexedFreeListHelper(size_t size);
|
||||
FreeChunk* getChunkFromIndexedFreeListHelper(size_t size, bool replenish = true);
|
||||
|
||||
// Get a chunk from the indexed free list. If the indexed free list
|
||||
// does not have a free chunk, try to replenish the indexed free list
|
||||
@ -430,10 +428,6 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
void initialize_sequential_subtasks_for_marking(int n_threads,
|
||||
HeapWord* low = NULL);
|
||||
|
||||
#if CFLS_LAB_REFILL_STATS
|
||||
void print_par_alloc_stats();
|
||||
#endif
|
||||
|
||||
// Space enquiries
|
||||
size_t used() const;
|
||||
size_t free() const;
|
||||
@ -617,6 +611,12 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
// Do some basic checks on the the free lists.
|
||||
void checkFreeListConsistency() const PRODUCT_RETURN;
|
||||
|
||||
// Printing support
|
||||
void dump_at_safepoint_with_locks(CMSCollector* c, outputStream* st);
|
||||
void print_indexed_free_lists(outputStream* st) const;
|
||||
void print_dictionary_free_lists(outputStream* st) const;
|
||||
void print_promo_info_blocks(outputStream* st) const;
|
||||
|
||||
NOT_PRODUCT (
|
||||
void initializeIndexedFreeListArrayReturnedBytes();
|
||||
size_t sumIndexedFreeListArrayReturnedBytes();
|
||||
@ -638,8 +638,9 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
|
||||
// Statistics functions
|
||||
// Initialize census for lists before the sweep.
|
||||
void beginSweepFLCensus(float sweep_current,
|
||||
float sweep_estimate);
|
||||
void beginSweepFLCensus(float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate);
|
||||
// Set the surplus for each of the free lists.
|
||||
void setFLSurplus();
|
||||
// Set the hint for each of the free lists.
|
||||
@ -730,16 +731,17 @@ class CFLS_LAB : public CHeapObj {
|
||||
FreeList _indexedFreeList[CompactibleFreeListSpace::IndexSetSize];
|
||||
|
||||
// Initialized from a command-line arg.
|
||||
size_t _blocks_to_claim;
|
||||
|
||||
#if CFLS_LAB_REFILL_STATS
|
||||
// Some statistics.
|
||||
int _refills;
|
||||
int _blocksTaken;
|
||||
static int _tot_refills;
|
||||
static int _tot_blocksTaken;
|
||||
static int _next_threshold;
|
||||
#endif
|
||||
// Allocation statistics in support of dynamic adjustment of
|
||||
// #blocks to claim per get_from_global_pool() call below.
|
||||
static AdaptiveWeightedAverage
|
||||
_blocks_to_claim [CompactibleFreeListSpace::IndexSetSize];
|
||||
static size_t _global_num_blocks [CompactibleFreeListSpace::IndexSetSize];
|
||||
static int _global_num_workers[CompactibleFreeListSpace::IndexSetSize];
|
||||
size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize];
|
||||
|
||||
// Internal work method
|
||||
void get_from_global_pool(size_t word_sz, FreeList* fl);
|
||||
|
||||
public:
|
||||
CFLS_LAB(CompactibleFreeListSpace* cfls);
|
||||
@ -748,7 +750,12 @@ public:
|
||||
HeapWord* alloc(size_t word_sz);
|
||||
|
||||
// Return any unused portions of the buffer to the global pool.
|
||||
void retire();
|
||||
void retire(int tid);
|
||||
|
||||
// Dynamic OldPLABSize sizing
|
||||
static void compute_desired_plab_size();
|
||||
// When the settings are modified from default static initialization
|
||||
static void modify_initialization(size_t n, unsigned wt);
|
||||
};
|
||||
|
||||
size_t PromotionInfo::refillSize() const {
|
||||
|
@ -253,7 +253,6 @@ void ConcurrentMarkSweepGeneration::init_initiating_occupancy(intx io, intx tr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConcurrentMarkSweepGeneration::ref_processor_init() {
|
||||
assert(collector() != NULL, "no collector");
|
||||
collector()->ref_processor_init();
|
||||
@ -341,6 +340,14 @@ CMSStats::CMSStats(ConcurrentMarkSweepGeneration* cms_gen, unsigned int alpha):
|
||||
_icms_duty_cycle = CMSIncrementalDutyCycle;
|
||||
}
|
||||
|
||||
double CMSStats::cms_free_adjustment_factor(size_t free) const {
|
||||
// TBD: CR 6909490
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
void CMSStats::adjust_cms_free_adjustment_factor(bool fail, size_t free) {
|
||||
}
|
||||
|
||||
// If promotion failure handling is on use
|
||||
// the padded average size of the promotion for each
|
||||
// young generation collection.
|
||||
@ -361,7 +368,11 @@ double CMSStats::time_until_cms_gen_full() const {
|
||||
|
||||
// Adjust by the safety factor.
|
||||
double cms_free_dbl = (double)cms_free;
|
||||
cms_free_dbl = cms_free_dbl * (100.0 - CMSIncrementalSafetyFactor) / 100.0;
|
||||
double cms_adjustment = (100.0 - CMSIncrementalSafetyFactor)/100.0;
|
||||
// Apply a further correction factor which tries to adjust
|
||||
// for recent occurance of concurrent mode failures.
|
||||
cms_adjustment = cms_adjustment * cms_free_adjustment_factor(cms_free);
|
||||
cms_free_dbl = cms_free_dbl * cms_adjustment;
|
||||
|
||||
if (PrintGCDetails && Verbose) {
|
||||
gclog_or_tty->print_cr("CMSStats::time_until_cms_gen_full: cms_free "
|
||||
@ -395,6 +406,8 @@ double CMSStats::time_until_cms_start() const {
|
||||
// late.
|
||||
double work = cms_duration() + gc0_period();
|
||||
double deadline = time_until_cms_gen_full();
|
||||
// If a concurrent mode failure occurred recently, we want to be
|
||||
// more conservative and halve our expected time_until_cms_gen_full()
|
||||
if (work > deadline) {
|
||||
if (Verbose && PrintGCDetails) {
|
||||
gclog_or_tty->print(
|
||||
@ -556,7 +569,8 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
_should_unload_classes(false),
|
||||
_concurrent_cycles_since_last_unload(0),
|
||||
_roots_scanning_options(0),
|
||||
_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding)
|
||||
_inter_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding),
|
||||
_intra_sweep_estimate(CMS_SweepWeight, CMS_SweepPadding)
|
||||
{
|
||||
if (ExplicitGCInvokesConcurrentAndUnloadsClasses) {
|
||||
ExplicitGCInvokesConcurrent = true;
|
||||
@ -773,7 +787,7 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
NOT_PRODUCT(_overflow_counter = CMSMarkStackOverflowInterval;)
|
||||
_gc_counters = new CollectorCounters("CMS", 1);
|
||||
_completed_initialization = true;
|
||||
_sweep_timer.start(); // start of time
|
||||
_inter_sweep_timer.start(); // start of time
|
||||
}
|
||||
|
||||
const char* ConcurrentMarkSweepGeneration::name() const {
|
||||
@ -900,6 +914,14 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(
|
||||
return result;
|
||||
}
|
||||
|
||||
// At a promotion failure dump information on block layout in heap
|
||||
// (cms old generation).
|
||||
void ConcurrentMarkSweepGeneration::promotion_failure_occurred() {
|
||||
if (CMSDumpAtPromotionFailure) {
|
||||
cmsSpace()->dump_at_safepoint_with_locks(collector(), gclog_or_tty);
|
||||
}
|
||||
}
|
||||
|
||||
CompactibleSpace*
|
||||
ConcurrentMarkSweepGeneration::first_compaction_space() const {
|
||||
return _cmsSpace;
|
||||
@ -1368,12 +1390,7 @@ void
|
||||
ConcurrentMarkSweepGeneration::
|
||||
par_promote_alloc_done(int thread_num) {
|
||||
CMSParGCThreadState* ps = _par_gc_thread_states[thread_num];
|
||||
ps->lab.retire();
|
||||
#if CFLS_LAB_REFILL_STATS
|
||||
if (thread_num == 0) {
|
||||
_cmsSpace->print_par_alloc_stats();
|
||||
}
|
||||
#endif
|
||||
ps->lab.retire(thread_num);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1974,11 +1991,14 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||
// We must adjust the allocation statistics being maintained
|
||||
// in the free list space. We do so by reading and clearing
|
||||
// the sweep timer and updating the block flux rate estimates below.
|
||||
assert(_sweep_timer.is_active(), "We should never see the timer inactive");
|
||||
_sweep_timer.stop();
|
||||
// Note that we do not use this sample to update the _sweep_estimate.
|
||||
_cmsGen->cmsSpace()->beginSweepFLCensus((float)(_sweep_timer.seconds()),
|
||||
_sweep_estimate.padded_average());
|
||||
assert(!_intra_sweep_timer.is_active(), "_intra_sweep_timer should be inactive");
|
||||
if (_inter_sweep_timer.is_active()) {
|
||||
_inter_sweep_timer.stop();
|
||||
// Note that we do not use this sample to update the _inter_sweep_estimate.
|
||||
_cmsGen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
|
||||
_inter_sweep_estimate.padded_average(),
|
||||
_intra_sweep_estimate.padded_average());
|
||||
}
|
||||
|
||||
GenMarkSweep::invoke_at_safepoint(_cmsGen->level(),
|
||||
ref_processor(), clear_all_soft_refs);
|
||||
@ -2015,10 +2035,10 @@ void CMSCollector::do_compaction_work(bool clear_all_soft_refs) {
|
||||
}
|
||||
|
||||
// Adjust the per-size allocation stats for the next epoch.
|
||||
_cmsGen->cmsSpace()->endSweepFLCensus(sweepCount() /* fake */);
|
||||
// Restart the "sweep timer" for next epoch.
|
||||
_sweep_timer.reset();
|
||||
_sweep_timer.start();
|
||||
_cmsGen->cmsSpace()->endSweepFLCensus(sweep_count() /* fake */);
|
||||
// Restart the "inter sweep timer" for the next epoch.
|
||||
_inter_sweep_timer.reset();
|
||||
_inter_sweep_timer.start();
|
||||
|
||||
// Sample collection pause time and reset for collection interval.
|
||||
if (UseAdaptiveSizePolicy) {
|
||||
@ -2676,7 +2696,7 @@ void ConcurrentMarkSweepGeneration::gc_epilogue(bool full) {
|
||||
// Also reset promotion tracking in par gc thread states.
|
||||
if (ParallelGCThreads > 0) {
|
||||
for (uint i = 0; i < ParallelGCThreads; i++) {
|
||||
_par_gc_thread_states[i]->promo.stopTrackingPromotions();
|
||||
_par_gc_thread_states[i]->promo.stopTrackingPromotions(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2771,7 +2791,7 @@ class VerifyMarkedClosure: public BitMapClosure {
|
||||
bool do_bit(size_t offset) {
|
||||
HeapWord* addr = _marks->offsetToHeapWord(offset);
|
||||
if (!_marks->isMarked(addr)) {
|
||||
oop(addr)->print();
|
||||
oop(addr)->print_on(gclog_or_tty);
|
||||
gclog_or_tty->print_cr(" ("INTPTR_FORMAT" should have been marked)", addr);
|
||||
_failed = true;
|
||||
}
|
||||
@ -2820,7 +2840,7 @@ bool CMSCollector::verify_after_remark() {
|
||||
// Clear any marks from a previous round
|
||||
verification_mark_bm()->clear_all();
|
||||
assert(verification_mark_stack()->isEmpty(), "markStack should be empty");
|
||||
assert(overflow_list_is_empty(), "overflow list should be empty");
|
||||
verify_work_stacks_empty();
|
||||
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
gch->ensure_parsability(false); // fill TLABs, but no need to retire them
|
||||
@ -2893,8 +2913,8 @@ void CMSCollector::verify_after_remark_work_1() {
|
||||
verification_mark_bm()->iterate(&vcl);
|
||||
if (vcl.failed()) {
|
||||
gclog_or_tty->print("Verification failed");
|
||||
Universe::heap()->print();
|
||||
fatal(" ... aborting");
|
||||
Universe::heap()->print_on(gclog_or_tty);
|
||||
fatal("CMS: failed marking verification after remark");
|
||||
}
|
||||
}
|
||||
|
||||
@ -3314,7 +3334,7 @@ bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) {
|
||||
Universe::heap()->barrier_set()->resize_covered_region(mr);
|
||||
// Hmmmm... why doesn't CFLS::set_end verify locking?
|
||||
// This is quite ugly; FIX ME XXX
|
||||
_cmsSpace->assert_locked();
|
||||
_cmsSpace->assert_locked(freelistLock());
|
||||
_cmsSpace->set_end((HeapWord*)_virtual_space.high());
|
||||
|
||||
// update the space and generation capacity counters
|
||||
@ -5868,9 +5888,9 @@ void CMSCollector::sweep(bool asynch) {
|
||||
check_correct_thread_executing();
|
||||
verify_work_stacks_empty();
|
||||
verify_overflow_empty();
|
||||
incrementSweepCount();
|
||||
_sweep_timer.stop();
|
||||
_sweep_estimate.sample(_sweep_timer.seconds());
|
||||
increment_sweep_count();
|
||||
_inter_sweep_timer.stop();
|
||||
_inter_sweep_estimate.sample(_inter_sweep_timer.seconds());
|
||||
size_policy()->avg_cms_free_at_sweep()->sample(_cmsGen->free());
|
||||
|
||||
// PermGen verification support: If perm gen sweeping is disabled in
|
||||
@ -5893,6 +5913,9 @@ void CMSCollector::sweep(bool asynch) {
|
||||
}
|
||||
}
|
||||
|
||||
assert(!_intra_sweep_timer.is_active(), "Should not be active");
|
||||
_intra_sweep_timer.reset();
|
||||
_intra_sweep_timer.start();
|
||||
if (asynch) {
|
||||
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
|
||||
CMSPhaseAccounting pa(this, "sweep", !PrintGCDetails);
|
||||
@ -5937,8 +5960,11 @@ void CMSCollector::sweep(bool asynch) {
|
||||
verify_work_stacks_empty();
|
||||
verify_overflow_empty();
|
||||
|
||||
_sweep_timer.reset();
|
||||
_sweep_timer.start();
|
||||
_intra_sweep_timer.stop();
|
||||
_intra_sweep_estimate.sample(_intra_sweep_timer.seconds());
|
||||
|
||||
_inter_sweep_timer.reset();
|
||||
_inter_sweep_timer.start();
|
||||
|
||||
update_time_of_last_gc(os::javaTimeMillis());
|
||||
|
||||
@ -5981,11 +6007,11 @@ void CMSCollector::sweep(bool asynch) {
|
||||
// FIX ME!!! Looks like this belongs in CFLSpace, with
|
||||
// CMSGen merely delegating to it.
|
||||
void ConcurrentMarkSweepGeneration::setNearLargestChunk() {
|
||||
double nearLargestPercent = 0.999;
|
||||
double nearLargestPercent = FLSLargestBlockCoalesceProximity;
|
||||
HeapWord* minAddr = _cmsSpace->bottom();
|
||||
HeapWord* largestAddr =
|
||||
(HeapWord*) _cmsSpace->dictionary()->findLargestDict();
|
||||
if (largestAddr == 0) {
|
||||
if (largestAddr == NULL) {
|
||||
// The dictionary appears to be empty. In this case
|
||||
// try to coalesce at the end of the heap.
|
||||
largestAddr = _cmsSpace->end();
|
||||
@ -5993,6 +6019,13 @@ void ConcurrentMarkSweepGeneration::setNearLargestChunk() {
|
||||
size_t largestOffset = pointer_delta(largestAddr, minAddr);
|
||||
size_t nearLargestOffset =
|
||||
(size_t)((double)largestOffset * nearLargestPercent) - MinChunkSize;
|
||||
if (PrintFLSStatistics != 0) {
|
||||
gclog_or_tty->print_cr(
|
||||
"CMS: Large Block: " PTR_FORMAT ";"
|
||||
" Proximity: " PTR_FORMAT " -> " PTR_FORMAT,
|
||||
largestAddr,
|
||||
_cmsSpace->nearLargestChunk(), minAddr + nearLargestOffset);
|
||||
}
|
||||
_cmsSpace->set_nearLargestChunk(minAddr + nearLargestOffset);
|
||||
}
|
||||
|
||||
@ -6072,9 +6105,11 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
|
||||
assert_lock_strong(gen->freelistLock());
|
||||
assert_lock_strong(bitMapLock());
|
||||
|
||||
assert(!_sweep_timer.is_active(), "Was switched off in an outer context");
|
||||
gen->cmsSpace()->beginSweepFLCensus((float)(_sweep_timer.seconds()),
|
||||
_sweep_estimate.padded_average());
|
||||
assert(!_inter_sweep_timer.is_active(), "Was switched off in an outer context");
|
||||
assert(_intra_sweep_timer.is_active(), "Was switched on in an outer context");
|
||||
gen->cmsSpace()->beginSweepFLCensus((float)(_inter_sweep_timer.seconds()),
|
||||
_inter_sweep_estimate.padded_average(),
|
||||
_intra_sweep_estimate.padded_average());
|
||||
gen->setNearLargestChunk();
|
||||
|
||||
{
|
||||
@ -6087,7 +6122,7 @@ void CMSCollector::sweepWork(ConcurrentMarkSweepGeneration* gen,
|
||||
// end-of-sweep-census below will be off by a little bit.
|
||||
}
|
||||
gen->cmsSpace()->sweep_completed();
|
||||
gen->cmsSpace()->endSweepFLCensus(sweepCount());
|
||||
gen->cmsSpace()->endSweepFLCensus(sweep_count());
|
||||
if (should_unload_classes()) { // unloaded classes this cycle,
|
||||
_concurrent_cycles_since_last_unload = 0; // ... reset count
|
||||
} else { // did not unload classes,
|
||||
|
@ -355,6 +355,11 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
|
||||
unsigned int new_duty_cycle);
|
||||
unsigned int icms_update_duty_cycle_impl();
|
||||
|
||||
// In support of adjusting of cms trigger ratios based on history
|
||||
// of concurrent mode failure.
|
||||
double cms_free_adjustment_factor(size_t free) const;
|
||||
void adjust_cms_free_adjustment_factor(bool fail, size_t free);
|
||||
|
||||
public:
|
||||
CMSStats(ConcurrentMarkSweepGeneration* cms_gen,
|
||||
unsigned int alpha = CMSExpAvgFactor);
|
||||
@ -570,8 +575,11 @@ class CMSCollector: public CHeapObj {
|
||||
// appropriately.
|
||||
void check_gc_time_limit();
|
||||
// XXX Move these to CMSStats ??? FIX ME !!!
|
||||
elapsedTimer _sweep_timer;
|
||||
AdaptivePaddedAverage _sweep_estimate;
|
||||
elapsedTimer _inter_sweep_timer; // time between sweeps
|
||||
elapsedTimer _intra_sweep_timer; // time _in_ sweeps
|
||||
// padded decaying average estimates of the above
|
||||
AdaptivePaddedAverage _inter_sweep_estimate;
|
||||
AdaptivePaddedAverage _intra_sweep_estimate;
|
||||
|
||||
protected:
|
||||
ConcurrentMarkSweepGeneration* _cmsGen; // old gen (CMS)
|
||||
@ -625,6 +633,7 @@ class CMSCollector: public CHeapObj {
|
||||
// . _collectorState <= Idling == post-sweep && pre-mark
|
||||
// . _collectorState in (Idling, Sweeping) == {initial,final}marking ||
|
||||
// precleaning || abortablePrecleanb
|
||||
public:
|
||||
enum CollectorState {
|
||||
Resizing = 0,
|
||||
Resetting = 1,
|
||||
@ -636,6 +645,7 @@ class CMSCollector: public CHeapObj {
|
||||
FinalMarking = 7,
|
||||
Sweeping = 8
|
||||
};
|
||||
protected:
|
||||
static CollectorState _collectorState;
|
||||
|
||||
// State related to prologue/epilogue invocation for my generations
|
||||
@ -655,7 +665,7 @@ class CMSCollector: public CHeapObj {
|
||||
|
||||
int _numYields;
|
||||
size_t _numDirtyCards;
|
||||
uint _sweepCount;
|
||||
size_t _sweep_count;
|
||||
// number of full gc's since the last concurrent gc.
|
||||
uint _full_gcs_since_conc_gc;
|
||||
|
||||
@ -905,7 +915,7 @@ class CMSCollector: public CHeapObj {
|
||||
|
||||
// Check that the currently executing thread is the expected
|
||||
// one (foreground collector or background collector).
|
||||
void check_correct_thread_executing() PRODUCT_RETURN;
|
||||
static void check_correct_thread_executing() PRODUCT_RETURN;
|
||||
// XXXPERM void print_statistics() PRODUCT_RETURN;
|
||||
|
||||
bool is_cms_reachable(HeapWord* addr);
|
||||
@ -930,8 +940,8 @@ class CMSCollector: public CHeapObj {
|
||||
static void set_foregroundGCShouldWait(bool v) { _foregroundGCShouldWait = v; }
|
||||
static bool foregroundGCIsActive() { return _foregroundGCIsActive; }
|
||||
static void set_foregroundGCIsActive(bool v) { _foregroundGCIsActive = v; }
|
||||
uint sweepCount() const { return _sweepCount; }
|
||||
void incrementSweepCount() { _sweepCount++; }
|
||||
size_t sweep_count() const { return _sweep_count; }
|
||||
void increment_sweep_count() { _sweep_count++; }
|
||||
|
||||
// Timers/stats for gc scheduling and incremental mode pacing.
|
||||
CMSStats& stats() { return _stats; }
|
||||
@ -1165,6 +1175,11 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||
virtual bool promotion_attempt_is_safe(size_t promotion_in_bytes,
|
||||
bool younger_handles_promotion_failure) const;
|
||||
|
||||
// Inform this (non-young) generation that a promotion failure was
|
||||
// encountered during a collection of a younger generation that
|
||||
// promotes into this generation.
|
||||
virtual void promotion_failure_occurred();
|
||||
|
||||
bool should_collect(bool full, size_t size, bool tlab);
|
||||
virtual bool should_concurrent_collect() const;
|
||||
virtual bool is_too_full() const;
|
||||
|
@ -55,7 +55,8 @@ class FreeBlockDictionary: public CHeapObj {
|
||||
virtual void dictCensusUpdate(size_t size, bool split, bool birth) = 0;
|
||||
virtual bool coalDictOverPopulated(size_t size) = 0;
|
||||
virtual void beginSweepDictCensus(double coalSurplusPercent,
|
||||
float sweep_current, float sweep_ewstimate) = 0;
|
||||
float inter_sweep_current, float inter_sweep_estimate,
|
||||
float intra__sweep_current) = 0;
|
||||
virtual void endSweepDictCensus(double splitSurplusPercent) = 0;
|
||||
virtual FreeChunk* findLargestDict() const = 0;
|
||||
// verify that the given chunk is in the dictionary.
|
||||
@ -79,6 +80,7 @@ class FreeBlockDictionary: public CHeapObj {
|
||||
}
|
||||
|
||||
virtual void printDictCensus() const = 0;
|
||||
virtual void print_free_lists(outputStream* st) const = 0;
|
||||
|
||||
virtual void verify() const = 0;
|
||||
|
||||
|
@ -67,3 +67,8 @@ void FreeChunk::verifyList() const {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void FreeChunk::print_on(outputStream* st) {
|
||||
st->print_cr("Next: " PTR_FORMAT " Prev: " PTR_FORMAT " %s",
|
||||
next(), prev(), cantCoalesce() ? "[can't coalesce]" : "");
|
||||
}
|
||||
|
@ -129,6 +129,8 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
|
||||
void verifyList() const PRODUCT_RETURN;
|
||||
void mangleAllocated(size_t size) PRODUCT_RETURN;
|
||||
void mangleFreed(size_t size) PRODUCT_RETURN;
|
||||
|
||||
void print_on(outputStream* st);
|
||||
};
|
||||
|
||||
// Alignment helpers etc.
|
||||
|
@ -81,8 +81,8 @@ void FreeList::reset(size_t hint) {
|
||||
set_hint(hint);
|
||||
}
|
||||
|
||||
void FreeList::init_statistics() {
|
||||
_allocation_stats.initialize();
|
||||
void FreeList::init_statistics(bool split_birth) {
|
||||
_allocation_stats.initialize(split_birth);
|
||||
}
|
||||
|
||||
FreeChunk* FreeList::getChunkAtHead() {
|
||||
@ -292,14 +292,31 @@ bool FreeList::verifyChunkInFreeLists(FreeChunk* fc) const {
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void FreeList::verify_stats() const {
|
||||
// The +1 of the LH comparand is to allow some "looseness" in
|
||||
// checking: we usually call this interface when adding a block
|
||||
// and we'll subsequently update the stats; we cannot update the
|
||||
// stats beforehand because in the case of the large-block BT
|
||||
// dictionary for example, this might be the first block and
|
||||
// in that case there would be no place that we could record
|
||||
// the stats (which are kept in the block itself).
|
||||
assert(_allocation_stats.prevSweep() + _allocation_stats.splitBirths() + 1 // Total Stock + 1
|
||||
>= _allocation_stats.splitDeaths() + (ssize_t)count(), "Conservation Principle");
|
||||
}
|
||||
|
||||
void FreeList::assert_proper_lock_protection_work() const {
|
||||
#ifdef ASSERT
|
||||
if (_protecting_lock != NULL &&
|
||||
SharedHeap::heap()->n_par_threads() > 0) {
|
||||
// Should become an assert.
|
||||
guarantee(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED");
|
||||
assert(_protecting_lock != NULL, "Don't call this directly");
|
||||
assert(ParallelGCThreads > 0, "Don't call this directly");
|
||||
Thread* thr = Thread::current();
|
||||
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
|
||||
// assert that we are holding the freelist lock
|
||||
} else if (thr->is_GC_task_thread()) {
|
||||
assert(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED");
|
||||
} else if (thr->is_Java_thread()) {
|
||||
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
|
||||
} else {
|
||||
ShouldNotReachHere(); // unaccounted thread type?
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -35,18 +35,26 @@ class CompactibleFreeListSpace;
|
||||
// for that implementation.
|
||||
|
||||
class Mutex;
|
||||
class TreeList;
|
||||
|
||||
class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||
friend class CompactibleFreeListSpace;
|
||||
friend class VMStructs;
|
||||
friend class printTreeCensusClosure;
|
||||
FreeChunk* _head; // List of free chunks
|
||||
friend class PrintTreeCensusClosure;
|
||||
|
||||
protected:
|
||||
TreeList* _parent;
|
||||
TreeList* _left;
|
||||
TreeList* _right;
|
||||
|
||||
private:
|
||||
FreeChunk* _head; // Head of list of free chunks
|
||||
FreeChunk* _tail; // Tail of list of free chunks
|
||||
size_t _size; // Size in Heap words of each chunks
|
||||
size_t _size; // Size in Heap words of each chunk
|
||||
ssize_t _count; // Number of entries in list
|
||||
size_t _hint; // next larger size list with a positive surplus
|
||||
|
||||
AllocationStats _allocation_stats; // statistics for smart allocation
|
||||
AllocationStats _allocation_stats; // allocation-related statistics
|
||||
|
||||
#ifdef ASSERT
|
||||
Mutex* _protecting_lock;
|
||||
@ -63,9 +71,12 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
// Initialize the allocation statistics.
|
||||
protected:
|
||||
void init_statistics();
|
||||
void init_statistics(bool split_birth = false);
|
||||
void set_count(ssize_t v) { _count = v;}
|
||||
void increment_count() { _count++; }
|
||||
void increment_count() {
|
||||
_count++;
|
||||
}
|
||||
|
||||
void decrement_count() {
|
||||
_count--;
|
||||
assert(_count >= 0, "Count should not be negative");
|
||||
@ -167,11 +178,13 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||
_allocation_stats.set_desired(v);
|
||||
}
|
||||
void compute_desired(float inter_sweep_current,
|
||||
float inter_sweep_estimate) {
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.compute_desired(_count,
|
||||
inter_sweep_current,
|
||||
inter_sweep_estimate);
|
||||
inter_sweep_estimate,
|
||||
intra_sweep_estimate);
|
||||
}
|
||||
ssize_t coalDesired() const {
|
||||
return _allocation_stats.coalDesired();
|
||||
@ -306,6 +319,9 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||
// found. Return NULL if "fc" is not found.
|
||||
bool verifyChunkInFreeLists(FreeChunk* fc) const;
|
||||
|
||||
// Stats verification
|
||||
void verify_stats() const PRODUCT_RETURN;
|
||||
|
||||
// Printing support
|
||||
static void print_labels_on(outputStream* st, const char* c);
|
||||
void print_on(outputStream* st, const char* c = NULL) const;
|
||||
|
@ -221,6 +221,7 @@ freeList.cpp freeList.hpp
|
||||
freeList.cpp globals.hpp
|
||||
freeList.cpp mutex.hpp
|
||||
freeList.cpp sharedHeap.hpp
|
||||
freeList.cpp vmThread.hpp
|
||||
|
||||
freeList.hpp allocationStats.hpp
|
||||
|
||||
|
@ -71,6 +71,7 @@ gcUtil.cpp gcUtil.hpp
|
||||
gcUtil.hpp allocation.hpp
|
||||
gcUtil.hpp debug.hpp
|
||||
gcUtil.hpp globalDefinitions.hpp
|
||||
gcUtil.hpp ostream.hpp
|
||||
gcUtil.hpp timer.hpp
|
||||
|
||||
generationCounters.cpp generationCounters.hpp
|
||||
|
@ -50,6 +50,7 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
|
||||
work_queue_set_, &term_),
|
||||
_is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
|
||||
_keep_alive_closure(&_scan_weak_ref_closure),
|
||||
_promotion_failure_size(0),
|
||||
_pushes(0), _pops(0), _steals(0), _steal_attempts(0), _term_attempts(0),
|
||||
_strong_roots_time(0.0), _term_time(0.0)
|
||||
{
|
||||
@ -249,6 +250,16 @@ void ParScanThreadState::undo_alloc_in_to_space(HeapWord* obj,
|
||||
}
|
||||
}
|
||||
|
||||
void ParScanThreadState::print_and_clear_promotion_failure_size() {
|
||||
if (_promotion_failure_size != 0) {
|
||||
if (PrintPromotionFailure) {
|
||||
gclog_or_tty->print(" (%d: promotion failure size = " SIZE_FORMAT ") ",
|
||||
_thread_num, _promotion_failure_size);
|
||||
}
|
||||
_promotion_failure_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ParScanThreadStateSet: private ResourceArray {
|
||||
public:
|
||||
// Initializes states for the specified number of threads;
|
||||
@ -260,11 +271,11 @@ public:
|
||||
GrowableArray<oop>** overflow_stacks_,
|
||||
size_t desired_plab_sz,
|
||||
ParallelTaskTerminator& term);
|
||||
inline ParScanThreadState& thread_sate(int i);
|
||||
inline ParScanThreadState& thread_state(int i);
|
||||
int pushes() { return _pushes; }
|
||||
int pops() { return _pops; }
|
||||
int steals() { return _steals; }
|
||||
void reset();
|
||||
void reset(bool promotion_failed);
|
||||
void flush();
|
||||
private:
|
||||
ParallelTaskTerminator& _term;
|
||||
@ -295,22 +306,31 @@ ParScanThreadStateSet::ParScanThreadStateSet(
|
||||
}
|
||||
}
|
||||
|
||||
inline ParScanThreadState& ParScanThreadStateSet::thread_sate(int i)
|
||||
inline ParScanThreadState& ParScanThreadStateSet::thread_state(int i)
|
||||
{
|
||||
assert(i >= 0 && i < length(), "sanity check!");
|
||||
return ((ParScanThreadState*)_data)[i];
|
||||
}
|
||||
|
||||
|
||||
void ParScanThreadStateSet::reset()
|
||||
void ParScanThreadStateSet::reset(bool promotion_failed)
|
||||
{
|
||||
_term.reset_for_reuse();
|
||||
if (promotion_failed) {
|
||||
for (int i = 0; i < length(); ++i) {
|
||||
thread_state(i).print_and_clear_promotion_failure_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParScanThreadStateSet::flush()
|
||||
{
|
||||
// Work in this loop should be kept as lightweight as
|
||||
// possible since this might otherwise become a bottleneck
|
||||
// to scaling. Should we add heavy-weight work into this
|
||||
// loop, consider parallelizing the loop into the worker threads.
|
||||
for (int i = 0; i < length(); ++i) {
|
||||
ParScanThreadState& par_scan_state = thread_sate(i);
|
||||
ParScanThreadState& par_scan_state = thread_state(i);
|
||||
|
||||
// Flush stats related to To-space PLAB activity and
|
||||
// retire the last buffer.
|
||||
@ -362,6 +382,14 @@ void ParScanThreadStateSet::flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (UseConcMarkSweepGC && ParallelGCThreads > 0) {
|
||||
// We need to call this even when ResizeOldPLAB is disabled
|
||||
// so as to avoid breaking some asserts. While we may be able
|
||||
// to avoid this by reorganizing the code a bit, I am loathe
|
||||
// to do that unless we find cases where ergo leads to bad
|
||||
// performance.
|
||||
CFLS_LAB::compute_desired_plab_size();
|
||||
}
|
||||
}
|
||||
|
||||
ParScanClosure::ParScanClosure(ParNewGeneration* g,
|
||||
@ -475,7 +503,7 @@ void ParNewGenTask::work(int i) {
|
||||
|
||||
Generation* old_gen = gch->next_gen(_gen);
|
||||
|
||||
ParScanThreadState& par_scan_state = _state_set->thread_sate(i);
|
||||
ParScanThreadState& par_scan_state = _state_set->thread_state(i);
|
||||
par_scan_state.set_young_old_boundary(_young_old_boundary);
|
||||
|
||||
par_scan_state.start_strong_roots();
|
||||
@ -659,7 +687,7 @@ void ParNewRefProcTaskProxy::work(int i)
|
||||
{
|
||||
ResourceMark rm;
|
||||
HandleMark hm;
|
||||
ParScanThreadState& par_scan_state = _state_set.thread_sate(i);
|
||||
ParScanThreadState& par_scan_state = _state_set.thread_state(i);
|
||||
par_scan_state.set_young_old_boundary(_young_old_boundary);
|
||||
_task.work(i, par_scan_state.is_alive_closure(),
|
||||
par_scan_state.keep_alive_closure(),
|
||||
@ -693,7 +721,7 @@ void ParNewRefProcTaskExecutor::execute(ProcessTask& task)
|
||||
ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(),
|
||||
_generation.reserved().end(), _state_set);
|
||||
workers->run_task(&rp_task);
|
||||
_state_set.reset();
|
||||
_state_set.reset(_generation.promotion_failed());
|
||||
}
|
||||
|
||||
void ParNewRefProcTaskExecutor::execute(EnqueueTask& task)
|
||||
@ -813,7 +841,7 @@ void ParNewGeneration::collect(bool full,
|
||||
GenCollectedHeap::StrongRootsScope srs(gch);
|
||||
tsk.work(0);
|
||||
}
|
||||
thread_state_set.reset();
|
||||
thread_state_set.reset(promotion_failed());
|
||||
|
||||
if (PAR_STATS_ENABLED && ParallelGCVerbose) {
|
||||
gclog_or_tty->print("Thread totals:\n"
|
||||
@ -882,6 +910,8 @@ void ParNewGeneration::collect(bool full,
|
||||
swap_spaces(); // Make life simpler for CMS || rescan; see 6483690.
|
||||
from()->set_next_compaction_space(to());
|
||||
gch->set_incremental_collection_will_fail();
|
||||
// Inform the next generation that a promotion failure occurred.
|
||||
_next_gen->promotion_failure_occurred();
|
||||
|
||||
// Reset the PromotionFailureALot counters.
|
||||
NOT_PRODUCT(Universe::heap()->reset_promotion_should_fail();)
|
||||
@ -1029,6 +1059,8 @@ oop ParNewGeneration::copy_to_survivor_space_avoiding_promotion_undo(
|
||||
new_obj = old;
|
||||
|
||||
preserve_mark_if_necessary(old, m);
|
||||
// Log the size of the maiden promotion failure
|
||||
par_scan_state->log_promotion_failure(sz);
|
||||
}
|
||||
|
||||
old->forward_to(new_obj);
|
||||
@ -1150,6 +1182,8 @@ oop ParNewGeneration::copy_to_survivor_space_with_undo(
|
||||
failed_to_promote = true;
|
||||
|
||||
preserve_mark_if_necessary(old, m);
|
||||
// Log the size of the maiden promotion failure
|
||||
par_scan_state->log_promotion_failure(sz);
|
||||
}
|
||||
} else {
|
||||
// Is in to-space; do copying ourselves.
|
||||
|
@ -97,6 +97,9 @@ class ParScanThreadState {
|
||||
int _pushes, _pops, _steals, _steal_attempts, _term_attempts;
|
||||
int _overflow_pushes, _overflow_refills, _overflow_refill_objs;
|
||||
|
||||
// Stats for promotion failure
|
||||
size_t _promotion_failure_size;
|
||||
|
||||
// Timing numbers.
|
||||
double _start;
|
||||
double _start_strong_roots;
|
||||
@ -169,6 +172,15 @@ class ParScanThreadState {
|
||||
// Undo the most recent allocation ("obj", of "word_sz").
|
||||
void undo_alloc_in_to_space(HeapWord* obj, size_t word_sz);
|
||||
|
||||
// Promotion failure stats
|
||||
size_t promotion_failure_size() { return promotion_failure_size(); }
|
||||
void log_promotion_failure(size_t sz) {
|
||||
if (_promotion_failure_size == 0) {
|
||||
_promotion_failure_size = sz;
|
||||
}
|
||||
}
|
||||
void print_and_clear_promotion_failure_size();
|
||||
|
||||
int pushes() { return _pushes; }
|
||||
int pops() { return _pops; }
|
||||
int steals() { return _steals; }
|
||||
|
@ -31,7 +31,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
// beginning of this sweep:
|
||||
// Count(end_last_sweep) - Count(start_this_sweep)
|
||||
// + splitBirths(between) - splitDeaths(between)
|
||||
// The above number divided by the time since the start [END???] of the
|
||||
// The above number divided by the time since the end of the
|
||||
// previous sweep gives us a time rate of demand for blocks
|
||||
// of this size. We compute a padded average of this rate as
|
||||
// our current estimate for the time rate of demand for blocks
|
||||
@ -41,7 +41,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
// estimates.
|
||||
AdaptivePaddedAverage _demand_rate_estimate;
|
||||
|
||||
ssize_t _desired; // Estimate computed as described above
|
||||
ssize_t _desired; // Demand stimate computed as described above
|
||||
ssize_t _coalDesired; // desired +/- small-percent for tuning coalescing
|
||||
|
||||
ssize_t _surplus; // count - (desired +/- small-percent),
|
||||
@ -53,9 +53,9 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
ssize_t _coalDeaths; // loss from coalescing
|
||||
ssize_t _splitBirths; // additional chunks from splitting
|
||||
ssize_t _splitDeaths; // loss from splitting
|
||||
size_t _returnedBytes; // number of bytes returned to list.
|
||||
size_t _returnedBytes; // number of bytes returned to list.
|
||||
public:
|
||||
void initialize() {
|
||||
void initialize(bool split_birth = false) {
|
||||
AdaptivePaddedAverage* dummy =
|
||||
new (&_demand_rate_estimate) AdaptivePaddedAverage(CMS_FLSWeight,
|
||||
CMS_FLSPadding);
|
||||
@ -67,7 +67,7 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
_beforeSweep = 0;
|
||||
_coalBirths = 0;
|
||||
_coalDeaths = 0;
|
||||
_splitBirths = 0;
|
||||
_splitBirths = split_birth? 1 : 0;
|
||||
_splitDeaths = 0;
|
||||
_returnedBytes = 0;
|
||||
}
|
||||
@ -75,10 +75,12 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
AllocationStats() {
|
||||
initialize();
|
||||
}
|
||||
|
||||
// The rate estimate is in blocks per second.
|
||||
void compute_desired(size_t count,
|
||||
float inter_sweep_current,
|
||||
float inter_sweep_estimate) {
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) {
|
||||
// If the latest inter-sweep time is below our granularity
|
||||
// of measurement, we may call in here with
|
||||
// inter_sweep_current == 0. However, even for suitably small
|
||||
@ -88,12 +90,31 @@ class AllocationStats VALUE_OBJ_CLASS_SPEC {
|
||||
// vulnerable to noisy glitches. In such cases, we
|
||||
// ignore the current sample and use currently available
|
||||
// historical estimates.
|
||||
// XXX NEEDS TO BE FIXED
|
||||
// assert(prevSweep() + splitBirths() >= splitDeaths() + (ssize_t)count, "Conservation Principle");
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// "Total Stock" "Not used at this block size"
|
||||
if (inter_sweep_current > _threshold) {
|
||||
ssize_t demand = prevSweep() - count + splitBirths() - splitDeaths();
|
||||
ssize_t demand = prevSweep() - (ssize_t)count + splitBirths() - splitDeaths();
|
||||
// XXX NEEDS TO BE FIXED
|
||||
// assert(demand >= 0, "Demand should be non-negative");
|
||||
// Defensive: adjust for imprecision in event counting
|
||||
if (demand < 0) {
|
||||
demand = 0;
|
||||
}
|
||||
float old_rate = _demand_rate_estimate.padded_average();
|
||||
float rate = ((float)demand)/inter_sweep_current;
|
||||
_demand_rate_estimate.sample(rate);
|
||||
_desired = (ssize_t)(_demand_rate_estimate.padded_average()
|
||||
*inter_sweep_estimate);
|
||||
float new_rate = _demand_rate_estimate.padded_average();
|
||||
ssize_t old_desired = _desired;
|
||||
_desired = (ssize_t)(new_rate * (inter_sweep_estimate
|
||||
+ CMSExtrapolateSweep
|
||||
? intra_sweep_estimate
|
||||
: 0.0));
|
||||
if (PrintFLSStatistics > 1) {
|
||||
gclog_or_tty->print_cr("demand: %d, old_rate: %f, current_rate: %f, new_rate: %f, old_desired: %d, new_desired: %d",
|
||||
demand, old_rate, rate, new_rate, old_desired, _desired);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,11 +52,35 @@ void AdaptiveWeightedAverage::sample(float new_sample) {
|
||||
_last_sample = new_sample;
|
||||
}
|
||||
|
||||
void AdaptiveWeightedAverage::print() const {
|
||||
print_on(tty);
|
||||
}
|
||||
|
||||
void AdaptiveWeightedAverage::print_on(outputStream* st) const {
|
||||
guarantee(false, "NYI");
|
||||
}
|
||||
|
||||
void AdaptivePaddedAverage::print() const {
|
||||
print_on(tty);
|
||||
}
|
||||
|
||||
void AdaptivePaddedAverage::print_on(outputStream* st) const {
|
||||
guarantee(false, "NYI");
|
||||
}
|
||||
|
||||
void AdaptivePaddedNoZeroDevAverage::print() const {
|
||||
print_on(tty);
|
||||
}
|
||||
|
||||
void AdaptivePaddedNoZeroDevAverage::print_on(outputStream* st) const {
|
||||
guarantee(false, "NYI");
|
||||
}
|
||||
|
||||
void AdaptivePaddedAverage::sample(float new_sample) {
|
||||
// Compute our parent classes sample information
|
||||
// Compute new adaptive weighted average based on new sample.
|
||||
AdaptiveWeightedAverage::sample(new_sample);
|
||||
|
||||
// Now compute the deviation and the new padded sample
|
||||
// Now update the deviation and the padded average.
|
||||
float new_avg = average();
|
||||
float new_dev = compute_adaptive_average(fabsd(new_sample - new_avg),
|
||||
deviation());
|
||||
|
@ -54,8 +54,8 @@ class AdaptiveWeightedAverage : public CHeapObj {
|
||||
|
||||
public:
|
||||
// Input weight must be between 0 and 100
|
||||
AdaptiveWeightedAverage(unsigned weight) :
|
||||
_average(0.0), _sample_count(0), _weight(weight), _last_sample(0.0) {
|
||||
AdaptiveWeightedAverage(unsigned weight, float avg = 0.0) :
|
||||
_average(avg), _sample_count(0), _weight(weight), _last_sample(0.0) {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
@ -64,6 +64,13 @@ class AdaptiveWeightedAverage : public CHeapObj {
|
||||
_last_sample = 0;
|
||||
}
|
||||
|
||||
// Useful for modifying static structures after startup.
|
||||
void modify(size_t avg, unsigned wt, bool force = false) {
|
||||
assert(force, "Are you sure you want to call this?");
|
||||
_average = (float)avg;
|
||||
_weight = wt;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
float average() const { return _average; }
|
||||
unsigned weight() const { return _weight; }
|
||||
@ -83,6 +90,10 @@ class AdaptiveWeightedAverage : public CHeapObj {
|
||||
// Convert to float and back to avoid integer overflow.
|
||||
return (size_t)exp_avg((float)avg, (float)sample, weight);
|
||||
}
|
||||
|
||||
// Printing
|
||||
void print_on(outputStream* st) const;
|
||||
void print() const;
|
||||
};
|
||||
|
||||
|
||||
@ -129,6 +140,10 @@ class AdaptivePaddedAverage : public AdaptiveWeightedAverage {
|
||||
|
||||
// Override
|
||||
void sample(float new_sample);
|
||||
|
||||
// Printing
|
||||
void print_on(outputStream* st) const;
|
||||
void print() const;
|
||||
};
|
||||
|
||||
// A weighted average that includes a deviation from the average,
|
||||
@ -146,7 +161,12 @@ public:
|
||||
AdaptivePaddedAverage(weight, padding) {}
|
||||
// Override
|
||||
void sample(float new_sample);
|
||||
|
||||
// Printing
|
||||
void print_on(outputStream* st) const;
|
||||
void print() const;
|
||||
};
|
||||
|
||||
// Use a least squares fit to a set of data to generate a linear
|
||||
// equation.
|
||||
// y = intercept + slope * x
|
||||
|
@ -274,7 +274,7 @@ CollectedHeap::fill_with_object_impl(HeapWord* start, size_t words)
|
||||
fill_with_array(start, words);
|
||||
} else if (words > 0) {
|
||||
assert(words == min_fill_size(), "unaligned size");
|
||||
post_allocation_setup_common(SystemDictionary::object_klass(), start,
|
||||
post_allocation_setup_common(SystemDictionary::Object_klass(), start,
|
||||
words);
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +155,9 @@ callGenerator.cpp callnode.hpp
|
||||
callGenerator.cpp cfgnode.hpp
|
||||
callGenerator.cpp compileLog.hpp
|
||||
callGenerator.cpp connode.hpp
|
||||
callGenerator.cpp ciCPCache.hpp
|
||||
callGenerator.cpp ciMethodHandle.hpp
|
||||
callGenerator.cpp javaClasses.hpp
|
||||
callGenerator.cpp parse.hpp
|
||||
callGenerator.cpp rootnode.hpp
|
||||
callGenerator.cpp runtime.hpp
|
||||
@ -391,6 +394,9 @@ divnode.hpp type.hpp
|
||||
|
||||
doCall.cpp addnode.hpp
|
||||
doCall.cpp callGenerator.hpp
|
||||
doCall.cpp ciCallSite.hpp
|
||||
doCall.cpp ciCPCache.hpp
|
||||
doCall.cpp ciMethodHandle.hpp
|
||||
doCall.cpp cfgnode.hpp
|
||||
doCall.cpp compileLog.hpp
|
||||
doCall.cpp linkResolver.hpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
// Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
@ -516,6 +516,11 @@ ciArrayKlassKlass.hpp ciKlassKlass.hpp
|
||||
|
||||
ciCallProfile.hpp ciClassList.hpp
|
||||
|
||||
ciCallSite.cpp ciCallSite.hpp
|
||||
ciCallSite.cpp ciUtilities.hpp
|
||||
|
||||
ciCallSite.hpp ciInstance.hpp
|
||||
|
||||
ciConstant.cpp allocation.hpp
|
||||
ciConstant.cpp allocation.inline.hpp
|
||||
ciConstant.cpp ciConstant.hpp
|
||||
@ -532,6 +537,12 @@ ciConstantPoolCache.cpp ciUtilities.hpp
|
||||
ciConstantPoolCache.hpp growableArray.hpp
|
||||
ciConstantPoolCache.hpp resourceArea.hpp
|
||||
|
||||
ciCPCache.cpp cpCacheOop.hpp
|
||||
ciCPCache.cpp ciCPCache.hpp
|
||||
|
||||
ciCPCache.hpp ciClassList.hpp
|
||||
ciCPCache.hpp ciObject.hpp
|
||||
|
||||
ciEnv.cpp allocation.inline.hpp
|
||||
ciEnv.cpp ciConstant.hpp
|
||||
ciEnv.cpp ciEnv.hpp
|
||||
@ -593,6 +604,7 @@ ciField.cpp universe.inline.hpp
|
||||
ciField.hpp ciClassList.hpp
|
||||
ciField.hpp ciConstant.hpp
|
||||
ciField.hpp ciFlags.hpp
|
||||
ciField.hpp ciInstance.hpp
|
||||
|
||||
ciFlags.cpp ciFlags.hpp
|
||||
|
||||
@ -679,6 +691,7 @@ ciMethod.hpp ciFlags.hpp
|
||||
ciMethod.hpp ciInstanceKlass.hpp
|
||||
ciMethod.hpp ciObject.hpp
|
||||
ciMethod.hpp ciSignature.hpp
|
||||
ciMethod.hpp methodHandles.hpp
|
||||
ciMethod.hpp methodLiveness.hpp
|
||||
|
||||
ciMethodBlocks.cpp bytecode.hpp
|
||||
@ -710,6 +723,15 @@ ciMethodKlass.cpp ciUtilities.hpp
|
||||
ciMethodKlass.hpp ciKlass.hpp
|
||||
ciMethodKlass.hpp ciSymbol.hpp
|
||||
|
||||
ciMethodHandle.cpp ciClassList.hpp
|
||||
ciMethodHandle.cpp ciInstance.hpp
|
||||
ciMethodHandle.cpp ciMethodHandle.hpp
|
||||
ciMethodHandle.cpp ciUtilities.hpp
|
||||
ciMethodHandle.cpp methodHandles.hpp
|
||||
ciMethodHandle.cpp methodHandleWalk.hpp
|
||||
|
||||
ciMethodHandle.hpp methodHandles.hpp
|
||||
|
||||
ciNullObject.cpp ciNullObject.hpp
|
||||
|
||||
ciNullObject.hpp ciClassList.hpp
|
||||
@ -755,11 +777,14 @@ ciObject.hpp handles.hpp
|
||||
ciObject.hpp jniHandles.hpp
|
||||
|
||||
ciObjectFactory.cpp allocation.inline.hpp
|
||||
ciObjectFactory.cpp ciCallSite.hpp
|
||||
ciObjectFactory.cpp ciCPCache.hpp
|
||||
ciObjectFactory.cpp ciInstance.hpp
|
||||
ciObjectFactory.cpp ciInstanceKlass.hpp
|
||||
ciObjectFactory.cpp ciInstanceKlassKlass.hpp
|
||||
ciObjectFactory.cpp ciMethod.hpp
|
||||
ciObjectFactory.cpp ciMethodData.hpp
|
||||
ciObjectFactory.cpp ciMethodHandle.hpp
|
||||
ciObjectFactory.cpp ciMethodKlass.hpp
|
||||
ciObjectFactory.cpp ciNullObject.hpp
|
||||
ciObjectFactory.cpp ciObjArray.hpp
|
||||
@ -793,6 +818,7 @@ ciSignature.hpp ciSymbol.hpp
|
||||
ciSignature.hpp globalDefinitions.hpp
|
||||
ciSignature.hpp growableArray.hpp
|
||||
|
||||
ciStreams.cpp ciCallSite.hpp
|
||||
ciStreams.cpp ciConstant.hpp
|
||||
ciStreams.cpp ciField.hpp
|
||||
ciStreams.cpp ciStreams.hpp
|
||||
@ -1499,6 +1525,7 @@ disassembler.cpp disassembler.hpp
|
||||
disassembler.cpp fprofiler.hpp
|
||||
disassembler.cpp handles.inline.hpp
|
||||
disassembler.cpp hpi.hpp
|
||||
disassembler.cpp javaClasses.hpp
|
||||
disassembler.cpp stubCodeGenerator.hpp
|
||||
disassembler.cpp stubRoutines.hpp
|
||||
|
||||
@ -2814,6 +2841,12 @@ methodDataOop.hpp oop.hpp
|
||||
methodDataOop.hpp orderAccess.hpp
|
||||
methodDataOop.hpp universe.hpp
|
||||
|
||||
methodHandleWalk.hpp methodHandles.hpp
|
||||
|
||||
methodHandleWalk.cpp methodHandleWalk.hpp
|
||||
methodHandleWalk.cpp oopFactory.hpp
|
||||
methodHandleWalk.cpp rewriter.hpp
|
||||
|
||||
methodHandles.hpp frame.inline.hpp
|
||||
methodHandles.hpp globals.hpp
|
||||
methodHandles.hpp interfaceSupport.hpp
|
||||
@ -3471,6 +3504,7 @@ reflection.cpp javaCalls.hpp
|
||||
reflection.cpp javaClasses.hpp
|
||||
reflection.cpp jvm.h
|
||||
reflection.cpp linkResolver.hpp
|
||||
reflection.cpp methodHandleWalk.hpp
|
||||
reflection.cpp objArrayKlass.hpp
|
||||
reflection.cpp objArrayOop.hpp
|
||||
reflection.cpp oopFactory.hpp
|
||||
|
@ -21,6 +21,8 @@
|
||||
// have any questions.
|
||||
//
|
||||
|
||||
arguments.cpp compactibleFreeListSpace.hpp
|
||||
|
||||
assembler_<arch>.cpp g1SATBCardTableModRefBS.hpp
|
||||
assembler_<arch>.cpp g1CollectedHeap.inline.hpp
|
||||
assembler_<arch>.cpp heapRegion.hpp
|
||||
|
@ -102,7 +102,9 @@ methodHandle Bytecode_invoke::static_target(TRAPS) {
|
||||
KlassHandle resolved_klass;
|
||||
constantPoolHandle constants(THREAD, _method->constants());
|
||||
|
||||
if (adjusted_invoke_code() != Bytecodes::_invokeinterface) {
|
||||
if (adjusted_invoke_code() == Bytecodes::_invokedynamic) {
|
||||
LinkResolver::resolve_dynamic_method(m, resolved_klass, constants, index(), CHECK_(methodHandle()));
|
||||
} else if (adjusted_invoke_code() != Bytecodes::_invokeinterface) {
|
||||
LinkResolver::resolve_method(m, resolved_klass, constants, index(), CHECK_(methodHandle()));
|
||||
} else {
|
||||
LinkResolver::resolve_interface_method(m, resolved_klass, constants, index(), CHECK_(methodHandle()));
|
||||
|
@ -205,12 +205,14 @@ class Bytecode_invoke: public ResourceObj {
|
||||
bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; }
|
||||
bool is_invokedynamic() const { return adjusted_invoke_code() == Bytecodes::_invokedynamic; }
|
||||
|
||||
bool has_receiver() const { return !is_invokestatic() && !is_invokedynamic(); }
|
||||
bool has_giant_index() const { return is_invokedynamic(); }
|
||||
|
||||
bool is_valid() const { return is_invokeinterface() ||
|
||||
is_invokevirtual() ||
|
||||
is_invokestatic() ||
|
||||
is_invokespecial(); }
|
||||
is_invokespecial() ||
|
||||
is_invokedynamic(); }
|
||||
|
||||
// Creation
|
||||
inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user