mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
Merge
This commit is contained in:
commit
98a91e2ab3
6 changed files with 201 additions and 57 deletions
|
@ -488,8 +488,8 @@ void VM_Version::get_processor_features() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The AES intrinsic stubs require AES instruction support (of course)
|
// The AES intrinsic stubs require AES instruction support (of course)
|
||||||
// but also require AVX mode for misaligned SSE access
|
// but also require AVX and sse3 modes for instructions it use.
|
||||||
if (UseAES && (UseAVX > 0)) {
|
if (UseAES && (UseAVX > 0) && (UseSSE > 2)) {
|
||||||
if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
||||||
UseAESIntrinsics = true;
|
UseAESIntrinsics = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -733,12 +733,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokehandle(JavaThread* thread)) {
|
||||||
get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
|
get_index_u2_cpcache(thread, bytecode), bytecode, CHECK);
|
||||||
} // end JvmtiHideSingleStepping
|
} // end JvmtiHideSingleStepping
|
||||||
|
|
||||||
cache_entry(thread)->set_method_handle(
|
cache_entry(thread)->set_method_handle(pool, info);
|
||||||
pool,
|
|
||||||
info.resolved_method(),
|
|
||||||
info.resolved_appendix(),
|
|
||||||
info.resolved_method_type(),
|
|
||||||
pool->resolved_references());
|
|
||||||
}
|
}
|
||||||
IRT_END
|
IRT_END
|
||||||
|
|
||||||
|
@ -762,12 +757,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
|
||||||
} // end JvmtiHideSingleStepping
|
} // end JvmtiHideSingleStepping
|
||||||
|
|
||||||
ConstantPoolCacheEntry* cp_cache_entry = pool->invokedynamic_cp_cache_entry_at(index);
|
ConstantPoolCacheEntry* cp_cache_entry = pool->invokedynamic_cp_cache_entry_at(index);
|
||||||
cp_cache_entry->set_dynamic_call(
|
cp_cache_entry->set_dynamic_call(pool, info);
|
||||||
pool,
|
|
||||||
info.resolved_method(),
|
|
||||||
info.resolved_appendix(),
|
|
||||||
info.resolved_method_type(),
|
|
||||||
pool->resolved_references());
|
|
||||||
}
|
}
|
||||||
IRT_END
|
IRT_END
|
||||||
|
|
||||||
|
|
|
@ -243,25 +243,17 @@ void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConstantPoolCacheEntry::set_method_handle(constantPoolHandle cpool,
|
void ConstantPoolCacheEntry::set_method_handle(constantPoolHandle cpool, const CallInfo &call_info) {
|
||||||
methodHandle adapter,
|
set_method_handle_common(cpool, Bytecodes::_invokehandle, call_info);
|
||||||
Handle appendix, Handle method_type,
|
|
||||||
objArrayHandle resolved_references) {
|
|
||||||
set_method_handle_common(cpool, Bytecodes::_invokehandle, adapter, appendix, method_type, resolved_references);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstantPoolCacheEntry::set_dynamic_call(constantPoolHandle cpool,
|
void ConstantPoolCacheEntry::set_dynamic_call(constantPoolHandle cpool, const CallInfo &call_info) {
|
||||||
methodHandle adapter,
|
set_method_handle_common(cpool, Bytecodes::_invokedynamic, call_info);
|
||||||
Handle appendix, Handle method_type,
|
|
||||||
objArrayHandle resolved_references) {
|
|
||||||
set_method_handle_common(cpool, Bytecodes::_invokedynamic, adapter, appendix, method_type, resolved_references);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
|
void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
|
||||||
Bytecodes::Code invoke_code,
|
Bytecodes::Code invoke_code,
|
||||||
methodHandle adapter,
|
const CallInfo &call_info) {
|
||||||
Handle appendix, Handle method_type,
|
|
||||||
objArrayHandle resolved_references) {
|
|
||||||
// NOTE: This CPCE can be the subject of data races.
|
// NOTE: This CPCE can be the subject of data races.
|
||||||
// There are three words to update: flags, refs[f2], f1 (in that order).
|
// There are three words to update: flags, refs[f2], f1 (in that order).
|
||||||
// Writers must store all other values before f1.
|
// Writers must store all other values before f1.
|
||||||
|
@ -276,6 +268,9 @@ void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const methodHandle adapter = call_info.resolved_method();
|
||||||
|
const Handle appendix = call_info.resolved_appendix();
|
||||||
|
const Handle method_type = call_info.resolved_method_type();
|
||||||
const bool has_appendix = appendix.not_null();
|
const bool has_appendix = appendix.not_null();
|
||||||
const bool has_method_type = method_type.not_null();
|
const bool has_method_type = method_type.not_null();
|
||||||
|
|
||||||
|
@ -315,6 +310,7 @@ void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
|
||||||
// This allows us to create fewer method oops, while keeping type safety.
|
// This allows us to create fewer method oops, while keeping type safety.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
objArrayHandle resolved_references = cpool->resolved_references();
|
||||||
// Store appendix, if any.
|
// Store appendix, if any.
|
||||||
if (has_appendix) {
|
if (has_appendix) {
|
||||||
const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset;
|
const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset;
|
||||||
|
|
|
@ -117,6 +117,8 @@ class PSPromotionManager;
|
||||||
// The fields are volatile so that they are stored in the order written in the
|
// The fields are volatile so that they are stored in the order written in the
|
||||||
// source code. The _indices field with the bytecode must be written last.
|
// source code. The _indices field with the bytecode must be written last.
|
||||||
|
|
||||||
|
class CallInfo;
|
||||||
|
|
||||||
class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
friend class constantPoolCacheKlass;
|
friend class constantPoolCacheKlass;
|
||||||
|
@ -223,18 +225,12 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
|
|
||||||
void set_method_handle(
|
void set_method_handle(
|
||||||
constantPoolHandle cpool, // holding constant pool (required for locking)
|
constantPoolHandle cpool, // holding constant pool (required for locking)
|
||||||
methodHandle method, // adapter for invokeExact, etc.
|
const CallInfo &call_info // Call link information
|
||||||
Handle appendix, // stored in refs[f2+0]; could be a java.lang.invoke.MethodType
|
|
||||||
Handle method_type, // stored in refs[f2+1]; is a java.lang.invoke.MethodType
|
|
||||||
objArrayHandle resolved_references
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void set_dynamic_call(
|
void set_dynamic_call(
|
||||||
constantPoolHandle cpool, // holding constant pool (required for locking)
|
constantPoolHandle cpool, // holding constant pool (required for locking)
|
||||||
methodHandle method, // adapter for this call site
|
const CallInfo &call_info // Call link information
|
||||||
Handle appendix, // stored in refs[f2+0]; could be a java.lang.invoke.CallSite
|
|
||||||
Handle method_type, // stored in refs[f2+1]; is a java.lang.invoke.MethodType
|
|
||||||
objArrayHandle resolved_references
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Common code for invokedynamic and MH invocations.
|
// Common code for invokedynamic and MH invocations.
|
||||||
|
@ -255,10 +251,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
void set_method_handle_common(
|
void set_method_handle_common(
|
||||||
constantPoolHandle cpool, // holding constant pool (required for locking)
|
constantPoolHandle cpool, // holding constant pool (required for locking)
|
||||||
Bytecodes::Code invoke_code, // _invokehandle or _invokedynamic
|
Bytecodes::Code invoke_code, // _invokehandle or _invokedynamic
|
||||||
methodHandle adapter, // invoker method (f1)
|
const CallInfo &call_info // Call link information
|
||||||
Handle appendix, // appendix such as CallSite, MethodType, etc. (refs[f2+0])
|
|
||||||
Handle method_type, // MethodType (refs[f2+1])
|
|
||||||
objArrayHandle resolved_references
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// invokedynamic and invokehandle call sites have two entries in the
|
// invokedynamic and invokehandle call sites have two entries in the
|
||||||
|
|
|
@ -1386,12 +1386,12 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va
|
||||||
// Non-escaped allocation returned from Java or runtime call have
|
// Non-escaped allocation returned from Java or runtime call have
|
||||||
// unknown values in fields.
|
// unknown values in fields.
|
||||||
for (EdgeIterator i(pta); i.has_next(); i.next()) {
|
for (EdgeIterator i(pta); i.has_next(); i.next()) {
|
||||||
PointsToNode* ptn = i.get();
|
PointsToNode* field = i.get();
|
||||||
if (ptn->is_Field() && ptn->as_Field()->is_oop()) {
|
if (field->is_Field() && field->as_Field()->is_oop()) {
|
||||||
if (add_edge(ptn, phantom_obj)) {
|
if (add_edge(field, phantom_obj)) {
|
||||||
// New edge was added
|
// New edge was added
|
||||||
new_edges++;
|
new_edges++;
|
||||||
add_field_uses_to_worklist(ptn->as_Field());
|
add_field_uses_to_worklist(field->as_Field());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1413,30 +1413,30 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va
|
||||||
// captured by Initialize node.
|
// captured by Initialize node.
|
||||||
//
|
//
|
||||||
for (EdgeIterator i(pta); i.has_next(); i.next()) {
|
for (EdgeIterator i(pta); i.has_next(); i.next()) {
|
||||||
PointsToNode* ptn = i.get(); // Field (AddP)
|
PointsToNode* field = i.get(); // Field (AddP)
|
||||||
if (!ptn->is_Field() || !ptn->as_Field()->is_oop())
|
if (!field->is_Field() || !field->as_Field()->is_oop())
|
||||||
continue; // Not oop field
|
continue; // Not oop field
|
||||||
int offset = ptn->as_Field()->offset();
|
int offset = field->as_Field()->offset();
|
||||||
if (offset == Type::OffsetBot) {
|
if (offset == Type::OffsetBot) {
|
||||||
if (!visited_bottom_offset) {
|
if (!visited_bottom_offset) {
|
||||||
// OffsetBot is used to reference array's element,
|
// OffsetBot is used to reference array's element,
|
||||||
// always add reference to NULL to all Field nodes since we don't
|
// always add reference to NULL to all Field nodes since we don't
|
||||||
// known which element is referenced.
|
// known which element is referenced.
|
||||||
if (add_edge(ptn, null_obj)) {
|
if (add_edge(field, null_obj)) {
|
||||||
// New edge was added
|
// New edge was added
|
||||||
new_edges++;
|
new_edges++;
|
||||||
add_field_uses_to_worklist(ptn->as_Field());
|
add_field_uses_to_worklist(field->as_Field());
|
||||||
visited_bottom_offset = true;
|
visited_bottom_offset = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check only oop fields.
|
// Check only oop fields.
|
||||||
const Type* adr_type = ptn->ideal_node()->as_AddP()->bottom_type();
|
const Type* adr_type = field->ideal_node()->as_AddP()->bottom_type();
|
||||||
if (adr_type->isa_rawptr()) {
|
if (adr_type->isa_rawptr()) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// Raw pointers are used for initializing stores so skip it
|
// Raw pointers are used for initializing stores so skip it
|
||||||
// since it should be recorded already
|
// since it should be recorded already
|
||||||
Node* base = get_addp_base(ptn->ideal_node());
|
Node* base = get_addp_base(field->ideal_node());
|
||||||
assert(adr_type->isa_rawptr() && base->is_Proj() &&
|
assert(adr_type->isa_rawptr() && base->is_Proj() &&
|
||||||
(base->in(0) == alloc),"unexpected pointer type");
|
(base->in(0) == alloc),"unexpected pointer type");
|
||||||
#endif
|
#endif
|
||||||
|
@ -1446,10 +1446,54 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va
|
||||||
offsets_worklist.append(offset);
|
offsets_worklist.append(offset);
|
||||||
Node* value = NULL;
|
Node* value = NULL;
|
||||||
if (ini != NULL) {
|
if (ini != NULL) {
|
||||||
BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
|
// StoreP::memory_type() == T_ADDRESS
|
||||||
Node* store = ini->find_captured_store(offset, type2aelembytes(ft), phase);
|
BasicType ft = UseCompressedOops ? T_NARROWOOP : T_ADDRESS;
|
||||||
if (store != NULL && store->is_Store()) {
|
Node* store = ini->find_captured_store(offset, type2aelembytes(ft, true), phase);
|
||||||
|
// Make sure initializing store has the same type as this AddP.
|
||||||
|
// This AddP may reference non existing field because it is on a
|
||||||
|
// dead branch of bimorphic call which is not eliminated yet.
|
||||||
|
if (store != NULL && store->is_Store() &&
|
||||||
|
store->as_Store()->memory_type() == ft) {
|
||||||
value = store->in(MemNode::ValueIn);
|
value = store->in(MemNode::ValueIn);
|
||||||
|
#ifdef ASSERT
|
||||||
|
if (VerifyConnectionGraph) {
|
||||||
|
// Verify that AddP already points to all objects the value points to.
|
||||||
|
PointsToNode* val = ptnode_adr(value->_idx);
|
||||||
|
assert((val != NULL), "should be processed already");
|
||||||
|
PointsToNode* missed_obj = NULL;
|
||||||
|
if (val->is_JavaObject()) {
|
||||||
|
if (!field->points_to(val->as_JavaObject())) {
|
||||||
|
missed_obj = val;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!val->is_LocalVar() || (val->edge_count() == 0)) {
|
||||||
|
tty->print_cr("----------init store has invalid value -----");
|
||||||
|
store->dump();
|
||||||
|
val->dump();
|
||||||
|
assert(val->is_LocalVar() && (val->edge_count() > 0), "should be processed already");
|
||||||
|
}
|
||||||
|
for (EdgeIterator j(val); j.has_next(); j.next()) {
|
||||||
|
PointsToNode* obj = j.get();
|
||||||
|
if (obj->is_JavaObject()) {
|
||||||
|
if (!field->points_to(obj->as_JavaObject())) {
|
||||||
|
missed_obj = obj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (missed_obj != NULL) {
|
||||||
|
tty->print_cr("----------field---------------------------------");
|
||||||
|
field->dump();
|
||||||
|
tty->print_cr("----------missed referernce to object-----------");
|
||||||
|
missed_obj->dump();
|
||||||
|
tty->print_cr("----------object referernced by init store -----");
|
||||||
|
store->dump();
|
||||||
|
val->dump();
|
||||||
|
assert(!field->points_to(missed_obj->as_JavaObject()), "missed JavaObject reference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
// There could be initializing stores which follow allocation.
|
// There could be initializing stores which follow allocation.
|
||||||
// For example, a volatile field store is not collected
|
// For example, a volatile field store is not collected
|
||||||
|
@ -1462,10 +1506,10 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va
|
||||||
}
|
}
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
// A field's initializing value was not recorded. Add NULL.
|
// A field's initializing value was not recorded. Add NULL.
|
||||||
if (add_edge(ptn, null_obj)) {
|
if (add_edge(field, null_obj)) {
|
||||||
// New edge was added
|
// New edge was added
|
||||||
new_edges++;
|
new_edges++;
|
||||||
add_field_uses_to_worklist(ptn->as_Field());
|
add_field_uses_to_worklist(field->as_Field());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1607,7 +1651,26 @@ void ConnectionGraph::verify_connection_graph(
|
||||||
}
|
}
|
||||||
// Verify that all fields have initializing values.
|
// Verify that all fields have initializing values.
|
||||||
if (field->edge_count() == 0) {
|
if (field->edge_count() == 0) {
|
||||||
|
tty->print_cr("----------field does not have references----------");
|
||||||
field->dump();
|
field->dump();
|
||||||
|
for (BaseIterator i(field); i.has_next(); i.next()) {
|
||||||
|
PointsToNode* base = i.get();
|
||||||
|
tty->print_cr("----------field has next base---------------------");
|
||||||
|
base->dump();
|
||||||
|
if (base->is_JavaObject() && (base != phantom_obj) && (base != null_obj)) {
|
||||||
|
tty->print_cr("----------base has fields-------------------------");
|
||||||
|
for (EdgeIterator j(base); j.has_next(); j.next()) {
|
||||||
|
j.get()->dump();
|
||||||
|
}
|
||||||
|
tty->print_cr("----------base has references---------------------");
|
||||||
|
for (UseIterator j(base); j.has_next(); j.next()) {
|
||||||
|
j.get()->dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (UseIterator i(field); i.has_next(); i.next()) {
|
||||||
|
i.get()->dump();
|
||||||
|
}
|
||||||
assert(field->edge_count() > 0, "sanity");
|
assert(field->edge_count() > 0, "sanity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1967,7 +2030,7 @@ bool PointsToNode::points_to(JavaObjectNode* ptn) const {
|
||||||
if (is_JavaObject()) {
|
if (is_JavaObject()) {
|
||||||
return (this == ptn);
|
return (this == ptn);
|
||||||
}
|
}
|
||||||
assert(is_LocalVar(), "sanity");
|
assert(is_LocalVar() || is_Field(), "sanity");
|
||||||
for (EdgeIterator i(this); i.has_next(); i.next()) {
|
for (EdgeIterator i(this); i.has_next(); i.next()) {
|
||||||
if (i.get() == ptn)
|
if (i.get() == ptn)
|
||||||
return true;
|
return true;
|
||||||
|
@ -3127,10 +3190,14 @@ void PointsToNode::dump(bool print_state) const {
|
||||||
EscapeState fields_es = fields_escape_state();
|
EscapeState fields_es = fields_escape_state();
|
||||||
tty->print("%s(%s) ", esc_names[(int)es], esc_names[(int)fields_es]);
|
tty->print("%s(%s) ", esc_names[(int)es], esc_names[(int)fields_es]);
|
||||||
if (nt == PointsToNode::JavaObject && !this->scalar_replaceable())
|
if (nt == PointsToNode::JavaObject && !this->scalar_replaceable())
|
||||||
tty->print("NSR");
|
tty->print("NSR ");
|
||||||
}
|
}
|
||||||
if (is_Field()) {
|
if (is_Field()) {
|
||||||
FieldNode* f = (FieldNode*)this;
|
FieldNode* f = (FieldNode*)this;
|
||||||
|
if (f->is_oop())
|
||||||
|
tty->print("oop ");
|
||||||
|
if (f->offset() > 0)
|
||||||
|
tty->print("+%d ", f->offset());
|
||||||
tty->print("(");
|
tty->print("(");
|
||||||
for (BaseIterator i(f); i.has_next(); i.next()) {
|
for (BaseIterator i(f); i.has_next(); i.next()) {
|
||||||
PointsToNode* b = i.get();
|
PointsToNode* b = i.get();
|
||||||
|
|
98
hotspot/test/compiler/8002069/Test8002069.java
Normal file
98
hotspot/test/compiler/8002069/Test8002069.java
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
* @bug 8002069
|
||||||
|
* @summary Assert failed in C2: assert(field->edge_count() > 0) failed: sanity
|
||||||
|
*
|
||||||
|
* @run main/othervm -Xmx32m -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:CompileCommand=exclude,Test8002069.dummy Test8002069
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class O {
|
||||||
|
int f;
|
||||||
|
public O() { f = 5; }
|
||||||
|
abstract void put(int i);
|
||||||
|
public int foo(int i) {
|
||||||
|
put(i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class A extends O {
|
||||||
|
int[] a;
|
||||||
|
public A(int s) {
|
||||||
|
a = new int[s];
|
||||||
|
}
|
||||||
|
public void put(int i) {
|
||||||
|
a[i%a.length] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends O {
|
||||||
|
int sz;
|
||||||
|
int[] a;
|
||||||
|
public B(int s) {
|
||||||
|
sz = s;
|
||||||
|
a = new int[s];
|
||||||
|
}
|
||||||
|
public void put(int i) {
|
||||||
|
a[i%sz] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Test8002069 {
|
||||||
|
public static void main(String args[]) {
|
||||||
|
int sum = 0;
|
||||||
|
for (int i=0; i<8000; i++) {
|
||||||
|
sum += test1(i);
|
||||||
|
}
|
||||||
|
for (int i=0; i<100000; i++) {
|
||||||
|
sum += test2(i);
|
||||||
|
}
|
||||||
|
System.out.println("PASSED. sum = " + sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
private O o;
|
||||||
|
|
||||||
|
private int foo(int i) {
|
||||||
|
return o.foo(i);
|
||||||
|
}
|
||||||
|
static int test1(int i) {
|
||||||
|
Test8002069 t = new Test8002069();
|
||||||
|
t.o = new A(5);
|
||||||
|
return t.foo(i);
|
||||||
|
}
|
||||||
|
static int test2(int i) {
|
||||||
|
Test8002069 t = new Test8002069();
|
||||||
|
t.o = new B(5);
|
||||||
|
dummy(i);
|
||||||
|
return t.foo(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dummy(int i) {
|
||||||
|
return i*2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue