Merge
This commit is contained in:
commit
343a64e0a0
@ -1221,12 +1221,19 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
|
||||
obj.load_item();
|
||||
|
||||
// info for exceptions
|
||||
CodeEmitInfo* info_for_exception = state_for(x);
|
||||
CodeEmitInfo* info_for_exception =
|
||||
(x->needs_exception_state() ? state_for(x) :
|
||||
state_for(x, x->state_before(), true /*ignore_xhandler*/));
|
||||
|
||||
CodeStub* stub;
|
||||
if (x->is_incompatible_class_change_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
|
||||
} else if (x->is_invokespecial_receiver_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new DeoptimizeStub(info_for_exception,
|
||||
Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_none);
|
||||
} else {
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
|
||||
}
|
||||
|
@ -1453,10 +1453,11 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) {
|
||||
ciKlass* k = op->klass();
|
||||
assert_different_registers(res, k_RInfo, klass_RInfo, Rtemp);
|
||||
|
||||
if (stub->is_simple_exception_stub()) {
|
||||
// TODO: ARM - Late binding is used to prevent confusion of register allocator
|
||||
assert(stub->is_exception_throw_stub(), "must be");
|
||||
((SimpleExceptionStub*)stub)->set_obj(op->result_opr());
|
||||
|
||||
}
|
||||
ciMethodData* md;
|
||||
ciProfileData* data;
|
||||
int mdo_offset_bias = 0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1412,12 +1412,20 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
|
||||
|
||||
obj.load_item();
|
||||
|
||||
CodeEmitInfo* info_for_exception = state_for(x);
|
||||
CodeEmitInfo* info_for_exception =
|
||||
(x->needs_exception_state() ? state_for(x) :
|
||||
state_for(x, x->state_before(), true /*ignore_xhandler*/));
|
||||
|
||||
CodeStub* stub;
|
||||
if (x->is_incompatible_class_change_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id,
|
||||
LIR_OprFact::illegalOpr, info_for_exception);
|
||||
} else if (x->is_invokespecial_receiver_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new DeoptimizeStub(info_for_exception,
|
||||
Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_none);
|
||||
} else {
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id,
|
||||
LIR_OprFact::illegalOpr, info_for_exception);
|
||||
|
@ -1131,12 +1131,19 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
|
||||
obj.load_item();
|
||||
LIR_Opr out_reg = rlock_result(x);
|
||||
CodeStub* stub;
|
||||
CodeEmitInfo* info_for_exception = state_for(x);
|
||||
CodeEmitInfo* info_for_exception =
|
||||
(x->needs_exception_state() ? state_for(x) :
|
||||
state_for(x, x->state_before(), true /*ignore_xhandler*/));
|
||||
|
||||
if (x->is_incompatible_class_change_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id,
|
||||
LIR_OprFact::illegalOpr, info_for_exception);
|
||||
} else if (x->is_invokespecial_receiver_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new DeoptimizeStub(info_for_exception,
|
||||
Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_none);
|
||||
} else {
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
|
||||
}
|
||||
|
@ -993,12 +993,19 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
|
||||
obj.load_item();
|
||||
|
||||
// info for exceptions
|
||||
CodeEmitInfo* info_for_exception = state_for (x);
|
||||
CodeEmitInfo* info_for_exception =
|
||||
(x->needs_exception_state() ? state_for(x) :
|
||||
state_for(x, x->state_before(), true /*ignore_xhandler*/));
|
||||
|
||||
CodeStub* stub;
|
||||
if (x->is_incompatible_class_change_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
|
||||
} else if (x->is_invokespecial_receiver_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new DeoptimizeStub(info_for_exception,
|
||||
Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_none);
|
||||
} else {
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
|
||||
}
|
||||
|
@ -1196,11 +1196,18 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
|
||||
obj.load_item();
|
||||
LIR_Opr out_reg = rlock_result(x);
|
||||
CodeStub* stub;
|
||||
CodeEmitInfo* info_for_exception = state_for(x);
|
||||
CodeEmitInfo* info_for_exception =
|
||||
(x->needs_exception_state() ? state_for(x) :
|
||||
state_for(x, x->state_before(), true /*ignore_xhandler*/));
|
||||
|
||||
if (x->is_incompatible_class_change_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
|
||||
} else if (x->is_invokespecial_receiver_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new DeoptimizeStub(info_for_exception,
|
||||
Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_none);
|
||||
} else {
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
|
||||
}
|
||||
|
@ -1429,12 +1429,17 @@ void LIRGenerator::do_CheckCast(CheckCast* x) {
|
||||
obj.load_item();
|
||||
|
||||
// info for exceptions
|
||||
CodeEmitInfo* info_for_exception = state_for(x);
|
||||
CodeEmitInfo* info_for_exception =
|
||||
(x->needs_exception_state() ? state_for(x) :
|
||||
state_for(x, x->state_before(), true /*ignore_xhandler*/));
|
||||
|
||||
CodeStub* stub;
|
||||
if (x->is_incompatible_class_change_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, info_for_exception);
|
||||
} else if (x->is_invokespecial_receiver_check()) {
|
||||
assert(patching_info == NULL, "can't patch this");
|
||||
stub = new DeoptimizeStub(info_for_exception, Deoptimization::Reason_class_check, Deoptimization::Action_none);
|
||||
} else {
|
||||
stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -763,12 +763,11 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
|
||||
}
|
||||
|
||||
if (supports_sse4_2()) {
|
||||
if (supports_sse4_2() && supports_clmul()) {
|
||||
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
|
||||
UseCRC32CIntrinsics = true;
|
||||
}
|
||||
}
|
||||
else if (UseCRC32CIntrinsics) {
|
||||
} else if (UseCRC32CIntrinsics) {
|
||||
if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
|
||||
warning("CRC32C intrinsics are not available on this CPU");
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ class CodeStub: public CompilationResourceObj {
|
||||
virtual bool is_exception_throw_stub() const { return false; }
|
||||
virtual bool is_range_check_stub() const { return false; }
|
||||
virtual bool is_divbyzero_stub() const { return false; }
|
||||
virtual bool is_simple_exception_stub() const { return false; }
|
||||
#ifndef PRODUCT
|
||||
virtual void print_name(outputStream* out) const = 0;
|
||||
#endif
|
||||
@ -483,6 +484,7 @@ class SimpleExceptionStub: public CodeStub {
|
||||
virtual void emit_code(LIR_Assembler* e);
|
||||
virtual CodeEmitInfo* info() const { return _info; }
|
||||
virtual bool is_exception_throw_stub() const { return true; }
|
||||
virtual bool is_simple_exception_stub() const { return true; }
|
||||
virtual void visit(LIR_OpVisitState* visitor) {
|
||||
if (_obj->is_valid()) visitor->do_input(_obj);
|
||||
visitor->do_slow_case(_info);
|
||||
|
@ -1829,6 +1829,20 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
log->identify(target),
|
||||
Bytecodes::name(code));
|
||||
|
||||
// invoke-special-super
|
||||
if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer()) {
|
||||
ciInstanceKlass* sender_klass =
|
||||
calling_klass->is_anonymous() ? calling_klass->host_klass() :
|
||||
calling_klass;
|
||||
if (sender_klass->is_interface()) {
|
||||
int index = state()->stack_size() - (target->arg_size_no_receiver() + 1);
|
||||
Value receiver = state()->stack_at(index);
|
||||
CheckCast* c = new CheckCast(sender_klass, receiver, copy_state_before());
|
||||
c->set_invokespecial_receiver_check();
|
||||
state()->stack_at_put(index, append_split(c));
|
||||
}
|
||||
}
|
||||
|
||||
// Some methods are obviously bindable without any type checks so
|
||||
// convert them directly to an invokespecial or invokestatic.
|
||||
if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) {
|
||||
|
@ -372,6 +372,7 @@ class Instruction: public CompilationResourceObj {
|
||||
UnorderedIsTrueFlag,
|
||||
NeedsPatchingFlag,
|
||||
ThrowIncompatibleClassChangeErrorFlag,
|
||||
InvokeSpecialReceiverCheckFlag,
|
||||
ProfileMDOFlag,
|
||||
IsLinkedInBlockFlag,
|
||||
NeedsRangeCheckFlag,
|
||||
@ -1454,6 +1455,16 @@ LEAF(CheckCast, TypeCheck)
|
||||
bool is_incompatible_class_change_check() const {
|
||||
return check_flag(ThrowIncompatibleClassChangeErrorFlag);
|
||||
}
|
||||
void set_invokespecial_receiver_check() {
|
||||
set_flag(InvokeSpecialReceiverCheckFlag, true);
|
||||
}
|
||||
bool is_invokespecial_receiver_check() const {
|
||||
return check_flag(InvokeSpecialReceiverCheckFlag);
|
||||
}
|
||||
|
||||
virtual bool needs_exception_state() const {
|
||||
return !is_invokespecial_receiver_check();
|
||||
}
|
||||
|
||||
ciType* declared_type() const;
|
||||
};
|
||||
|
@ -595,6 +595,16 @@ ciInstanceKlass* ciInstanceKlass::implementor() {
|
||||
return impl;
|
||||
}
|
||||
|
||||
ciInstanceKlass* ciInstanceKlass::host_klass() {
|
||||
assert(is_loaded(), "must be loaded");
|
||||
if (is_anonymous()) {
|
||||
VM_ENTRY_MARK
|
||||
Klass* host_klass = get_instanceKlass()->host_klass();
|
||||
return CURRENT_ENV->get_instance_klass(host_klass);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Utility class for printing of the contents of the static fields for
|
||||
// use by compilation replay. It only prints out the information that
|
||||
// could be consumed by the compiler, so for primitive types it prints
|
||||
|
@ -260,6 +260,8 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ciInstanceKlass* host_klass();
|
||||
|
||||
bool can_be_instantiated() {
|
||||
assert(is_loaded(), "must be loaded");
|
||||
return !is_interface() && !is_abstract();
|
||||
|
@ -951,6 +951,13 @@ bool ciMethod::is_compiled_lambda_form() const {
|
||||
return iid == vmIntrinsics::_compiledLambdaForm;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::is_object_initializer
|
||||
//
|
||||
bool ciMethod::is_object_initializer() const {
|
||||
return name() == ciSymbol::object_initializer_name();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::has_member_arg
|
||||
//
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -337,6 +337,7 @@ class ciMethod : public ciMetadata {
|
||||
bool has_reserved_stack_access() const { return _has_reserved_stack_access; }
|
||||
bool is_boxing_method() const;
|
||||
bool is_unboxing_method() const;
|
||||
bool is_object_initializer() const;
|
||||
|
||||
// Replay data methods
|
||||
void dump_name_as_ascii(outputStream* st);
|
||||
|
@ -720,7 +720,8 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte
|
||||
Thread* THREAD = thread;
|
||||
// extract receiver from the outgoing argument list if necessary
|
||||
Handle receiver(thread, NULL);
|
||||
if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface) {
|
||||
if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface ||
|
||||
bytecode == Bytecodes::_invokespecial) {
|
||||
ResourceMark rm(thread);
|
||||
methodHandle m (thread, method(thread));
|
||||
Bytecode_invoke call(m, bci(thread));
|
||||
@ -783,16 +784,25 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte
|
||||
int index = info.resolved_method()->itable_index();
|
||||
assert(info.itable_index() == index, "");
|
||||
}
|
||||
} else if (bytecode == Bytecodes::_invokespecial) {
|
||||
assert(info.call_kind() == CallInfo::direct_call, "must be direct call");
|
||||
} else {
|
||||
assert(info.call_kind() == CallInfo::direct_call ||
|
||||
info.call_kind() == CallInfo::vtable_call, "");
|
||||
}
|
||||
#endif
|
||||
// Get sender or sender's host_klass, and only set cpCache entry to resolved if
|
||||
// it is not an interface. The receiver for invokespecial calls within interface
|
||||
// methods must be checked for every call.
|
||||
InstanceKlass* sender = pool->pool_holder();
|
||||
sender = sender->is_anonymous() ? sender->host_klass() : sender;
|
||||
|
||||
switch (info.call_kind()) {
|
||||
case CallInfo::direct_call:
|
||||
cp_cache_entry->set_direct_call(
|
||||
bytecode,
|
||||
info.resolved_method());
|
||||
info.resolved_method(),
|
||||
sender->is_interface());
|
||||
break;
|
||||
case CallInfo::vtable_call:
|
||||
cp_cache_entry->set_vtable_call(
|
||||
|
@ -1057,12 +1057,14 @@ methodHandle LinkResolver::linktime_resolve_static_method(const LinkInfo& link_i
|
||||
|
||||
|
||||
void LinkResolver::resolve_special_call(CallInfo& result,
|
||||
Handle recv,
|
||||
const LinkInfo& link_info,
|
||||
TRAPS) {
|
||||
methodHandle resolved_method = linktime_resolve_special_method(link_info, CHECK);
|
||||
runtime_resolve_special_method(result, resolved_method,
|
||||
link_info.resolved_klass(),
|
||||
link_info.current_klass(),
|
||||
recv,
|
||||
link_info.check_access(), CHECK);
|
||||
}
|
||||
|
||||
@ -1149,6 +1151,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
|
||||
const methodHandle& resolved_method,
|
||||
KlassHandle resolved_klass,
|
||||
KlassHandle current_klass,
|
||||
Handle recv,
|
||||
bool check_access, TRAPS) {
|
||||
|
||||
// resolved method is selected method unless we have an old-style lookup
|
||||
@ -1157,21 +1160,19 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
|
||||
// no checks for shadowing
|
||||
methodHandle sel_method(THREAD, resolved_method());
|
||||
|
||||
// check if this is an old-style super call and do a new lookup if so
|
||||
{ KlassHandle method_klass = KlassHandle(THREAD,
|
||||
resolved_method->method_holder());
|
||||
if (check_access &&
|
||||
// check if the method is not <init>
|
||||
resolved_method->name() != vmSymbols::object_initializer_name()) {
|
||||
|
||||
if (check_access &&
|
||||
// check if this is an old-style super call and do a new lookup if so
|
||||
// a) check if ACC_SUPER flag is set for the current class
|
||||
(current_klass->is_super() || !AllowNonVirtualCalls) &&
|
||||
if ((current_klass->is_super() || !AllowNonVirtualCalls) &&
|
||||
// b) check if the class of the resolved_klass is a superclass
|
||||
// (not supertype in order to exclude interface classes) of the current class.
|
||||
// This check is not performed for super.invoke for interface methods
|
||||
// in super interfaces.
|
||||
current_klass->is_subclass_of(resolved_klass()) &&
|
||||
current_klass() != resolved_klass() &&
|
||||
// c) check if the method is not <init>
|
||||
resolved_method->name() != vmSymbols::object_initializer_name()) {
|
||||
current_klass() != resolved_klass()) {
|
||||
// Lookup super method
|
||||
KlassHandle super_klass(THREAD, current_klass->super());
|
||||
sel_method = lookup_instance_method_in_klasses(super_klass,
|
||||
@ -1186,6 +1187,27 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result,
|
||||
resolved_method->signature()));
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the class of objectref (the receiver) is the current class or interface,
|
||||
// or a subtype of the current class or interface (the sender), otherwise invokespecial
|
||||
// throws IllegalAccessError.
|
||||
// The verifier checks that the sender is a subtype of the class in the I/MR operand.
|
||||
// The verifier also checks that the receiver is a subtype of the sender, if the sender is
|
||||
// a class. If the sender is an interface, the check has to be performed at runtime.
|
||||
InstanceKlass* sender = InstanceKlass::cast(current_klass());
|
||||
sender = sender->is_anonymous() ? sender->host_klass() : sender;
|
||||
if (sender->is_interface() && recv.not_null()) {
|
||||
Klass* receiver_klass = recv->klass();
|
||||
if (!receiver_klass->is_subtype_of(sender)) {
|
||||
ResourceMark rm(THREAD);
|
||||
char buf[500];
|
||||
jio_snprintf(buf, sizeof(buf),
|
||||
"Receiver class %s must be the current class or a subtype of interface %s",
|
||||
receiver_klass->name()->as_C_string(),
|
||||
sender->name()->as_C_string());
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if not static
|
||||
@ -1518,7 +1540,7 @@ methodHandle LinkResolver::resolve_static_call_or_null(const LinkInfo& link_info
|
||||
methodHandle LinkResolver::resolve_special_call_or_null(const LinkInfo& link_info) {
|
||||
EXCEPTION_MARK;
|
||||
CallInfo info;
|
||||
resolve_special_call(info, link_info, THREAD);
|
||||
resolve_special_call(info, Handle(), link_info, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
return methodHandle();
|
||||
@ -1534,7 +1556,7 @@ methodHandle LinkResolver::resolve_special_call_or_null(const LinkInfo& link_inf
|
||||
void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) {
|
||||
switch (byte) {
|
||||
case Bytecodes::_invokestatic : resolve_invokestatic (result, pool, index, CHECK); break;
|
||||
case Bytecodes::_invokespecial : resolve_invokespecial (result, pool, index, CHECK); break;
|
||||
case Bytecodes::_invokespecial : resolve_invokespecial (result, recv, pool, index, CHECK); break;
|
||||
case Bytecodes::_invokevirtual : resolve_invokevirtual (result, recv, pool, index, CHECK); break;
|
||||
case Bytecodes::_invokehandle : resolve_invokehandle (result, pool, index, CHECK); break;
|
||||
case Bytecodes::_invokedynamic : resolve_invokedynamic (result, pool, index, CHECK); break;
|
||||
@ -1563,7 +1585,7 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv,
|
||||
resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK);
|
||||
break;
|
||||
case Bytecodes::_invokespecial:
|
||||
resolve_special_call(result, link_info, CHECK);
|
||||
resolve_special_call(result, recv, link_info, CHECK);
|
||||
break;
|
||||
default:
|
||||
fatal("bad call: %s", Bytecodes::name(byte));
|
||||
@ -1576,9 +1598,10 @@ void LinkResolver::resolve_invokestatic(CallInfo& result, const constantPoolHand
|
||||
}
|
||||
|
||||
|
||||
void LinkResolver::resolve_invokespecial(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
|
||||
void LinkResolver::resolve_invokespecial(CallInfo& result, Handle recv,
|
||||
const constantPoolHandle& pool, int index, TRAPS) {
|
||||
LinkInfo link_info(pool, index, CHECK);
|
||||
resolve_special_call(result, link_info, CHECK);
|
||||
resolve_special_call(result, recv, link_info, CHECK);
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,6 +230,7 @@ class LinkResolver: AllStatic {
|
||||
const methodHandle& resolved_method,
|
||||
KlassHandle resolved_klass,
|
||||
KlassHandle current_klass,
|
||||
Handle recv,
|
||||
bool check_access, TRAPS);
|
||||
static void runtime_resolve_virtual_method (CallInfo& result,
|
||||
const methodHandle& resolved_method,
|
||||
@ -256,7 +257,7 @@ class LinkResolver: AllStatic {
|
||||
// runtime resolving from constant pool
|
||||
static void resolve_invokestatic (CallInfo& result,
|
||||
const constantPoolHandle& pool, int index, TRAPS);
|
||||
static void resolve_invokespecial (CallInfo& result,
|
||||
static void resolve_invokespecial (CallInfo& result, Handle recv,
|
||||
const constantPoolHandle& pool, int index, TRAPS);
|
||||
static void resolve_invokevirtual (CallInfo& result, Handle recv,
|
||||
const constantPoolHandle& pool, int index, TRAPS);
|
||||
@ -289,6 +290,7 @@ class LinkResolver: AllStatic {
|
||||
const LinkInfo& link_info,
|
||||
bool initialize_klass, TRAPS);
|
||||
static void resolve_special_call (CallInfo& result,
|
||||
Handle recv,
|
||||
const LinkInfo& link_info,
|
||||
TRAPS);
|
||||
static void resolve_virtual_call (CallInfo& result, Handle recv, KlassHandle recv_klass,
|
||||
|
@ -140,7 +140,8 @@ void ConstantPoolCacheEntry::set_parameter_size(int value) {
|
||||
|
||||
void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code,
|
||||
methodHandle method,
|
||||
int vtable_index) {
|
||||
int vtable_index,
|
||||
bool sender_is_interface) {
|
||||
bool is_vtable_call = (vtable_index >= 0); // FIXME: split this method on this boolean
|
||||
assert(method->interpreter_entry() != NULL, "should have been set at this point");
|
||||
assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache");
|
||||
@ -204,7 +205,13 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co
|
||||
if (byte_no == 1) {
|
||||
assert(invoke_code != Bytecodes::_invokevirtual &&
|
||||
invoke_code != Bytecodes::_invokeinterface, "");
|
||||
// Don't mark invokespecial to method as resolved if sender is an interface. The receiver
|
||||
// has to be checked that it is a subclass of the current class every time this bytecode
|
||||
// is executed.
|
||||
if (invoke_code != Bytecodes::_invokespecial || !sender_is_interface ||
|
||||
method->name() == vmSymbols::object_initializer_name()) {
|
||||
set_bytecode_1(invoke_code);
|
||||
}
|
||||
} else if (byte_no == 2) {
|
||||
if (change_to_virtual) {
|
||||
assert(invoke_code == Bytecodes::_invokeinterface, "");
|
||||
@ -234,17 +241,18 @@ void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_co
|
||||
NOT_PRODUCT(verify(tty));
|
||||
}
|
||||
|
||||
void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method) {
|
||||
void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method,
|
||||
bool sender_is_interface) {
|
||||
int index = Method::nonvirtual_vtable_index;
|
||||
// index < 0; FIXME: inline and customize set_direct_or_vtable_call
|
||||
set_direct_or_vtable_call(invoke_code, method, index);
|
||||
set_direct_or_vtable_call(invoke_code, method, index, sender_is_interface);
|
||||
}
|
||||
|
||||
void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, methodHandle method, int index) {
|
||||
// either the method is a miranda or its holder should accept the given index
|
||||
assert(method->method_holder()->is_interface() || method->method_holder()->verify_vtable_index(index), "");
|
||||
// index >= 0; FIXME: inline and customize set_direct_or_vtable_call
|
||||
set_direct_or_vtable_call(invoke_code, method, index);
|
||||
set_direct_or_vtable_call(invoke_code, method, index, false);
|
||||
}
|
||||
|
||||
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, const methodHandle& method, int index) {
|
||||
|
@ -230,13 +230,15 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||
void set_direct_or_vtable_call(
|
||||
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
||||
methodHandle method, // the method/prototype if any (NULL, otherwise)
|
||||
int vtable_index // the vtable index if any, else negative
|
||||
int vtable_index, // the vtable index if any, else negative
|
||||
bool sender_is_interface
|
||||
);
|
||||
|
||||
public:
|
||||
void set_direct_call( // sets entry to exact concrete method entry
|
||||
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
||||
methodHandle method // the method to call
|
||||
methodHandle method, // the method to call
|
||||
bool sender_is_interface
|
||||
);
|
||||
|
||||
void set_vtable_call( // sets entry to vtable index
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -505,6 +505,30 @@ void Parse::do_call() {
|
||||
speculative_receiver_type = receiver_type != NULL ? receiver_type->speculative_type() : NULL;
|
||||
}
|
||||
|
||||
// invoke-super-special
|
||||
if (iter().cur_bc_raw() == Bytecodes::_invokespecial && !orig_callee->is_object_initializer()) {
|
||||
ciInstanceKlass* calling_klass = method()->holder();
|
||||
ciInstanceKlass* sender_klass =
|
||||
calling_klass->is_anonymous() ? calling_klass->host_klass() :
|
||||
calling_klass;
|
||||
if (sender_klass->is_interface()) {
|
||||
Node* receiver_node = stack(sp() - nargs);
|
||||
Node* cls_node = makecon(TypeKlassPtr::make(sender_klass));
|
||||
Node* bad_type_ctrl = NULL;
|
||||
Node* casted_receiver = gen_checkcast(receiver_node, cls_node, &bad_type_ctrl);
|
||||
if (bad_type_ctrl != NULL) {
|
||||
PreserveJVMState pjvms(this);
|
||||
set_control(bad_type_ctrl);
|
||||
uncommon_trap(Deoptimization::Reason_class_check,
|
||||
Deoptimization::Action_none);
|
||||
}
|
||||
if (stopped()) {
|
||||
return; // MUST uncommon-trap?
|
||||
}
|
||||
set_stack(sp() - nargs, casted_receiver);
|
||||
}
|
||||
}
|
||||
|
||||
// Note: It's OK to try to inline a virtual call.
|
||||
// The call generator will not attempt to inline a polymorphic call
|
||||
// unless it knows how to optimize the receiver dispatch.
|
||||
|
@ -61,6 +61,15 @@ const TypePtr *MemNode::adr_type() const {
|
||||
return calculate_adr_type(adr->bottom_type(), cross_check);
|
||||
}
|
||||
|
||||
bool MemNode::check_if_adr_maybe_raw(Node* adr) {
|
||||
if (adr != NULL) {
|
||||
if (adr->bottom_type()->base() == Type::RawPtr || adr->bottom_type()->base() == Type::AnyPtr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void MemNode::dump_spec(outputStream *st) const {
|
||||
if (in(Address) == NULL) return; // node is dead
|
||||
@ -560,6 +569,7 @@ Node* MemNode::find_previous_store(PhaseTransform* phase) {
|
||||
if (offset == Type::OffsetBot)
|
||||
return NULL; // cannot unalias unless there are precise offsets
|
||||
|
||||
const bool adr_maybe_raw = check_if_adr_maybe_raw(adr);
|
||||
const TypeOopPtr *addr_t = adr->bottom_type()->isa_oopptr();
|
||||
|
||||
intptr_t size_in_bytes = memory_size();
|
||||
@ -577,6 +587,13 @@ Node* MemNode::find_previous_store(PhaseTransform* phase) {
|
||||
Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_offset);
|
||||
if (st_base == NULL)
|
||||
break; // inscrutable pointer
|
||||
|
||||
// For raw accesses it's not enough to prove that constant offsets don't intersect.
|
||||
// We need the bases to be the equal in order for the offset check to make sense.
|
||||
if ((adr_maybe_raw || check_if_adr_maybe_raw(st_adr)) && st_base != base) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (st_offset != offset && st_offset != Type::OffsetBot) {
|
||||
const int MAX_STORE = BytesPerLong;
|
||||
if (st_offset >= offset + size_in_bytes ||
|
||||
|
@ -78,6 +78,7 @@ protected:
|
||||
}
|
||||
|
||||
virtual Node* find_previous_arraycopy(PhaseTransform* phase, Node* ld_alloc, Node*& mem, bool can_see_stored_value) const { return NULL; }
|
||||
static bool check_if_adr_maybe_raw(Node* adr);
|
||||
|
||||
public:
|
||||
// Helpers for the optimizer. Documented in memnode.cpp.
|
||||
|
@ -727,7 +727,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||
assert(!is_signature_polymorphic_static(mh_invoke_id), "");
|
||||
LinkResolver::resolve_handle_call(result, link_info, THREAD);
|
||||
} else if (ref_kind == JVM_REF_invokeSpecial) {
|
||||
LinkResolver::resolve_special_call(result,
|
||||
LinkResolver::resolve_special_call(result, Handle(),
|
||||
link_info, THREAD);
|
||||
} else if (ref_kind == JVM_REF_invokeVirtual) {
|
||||
LinkResolver::resolve_virtual_call(result, Handle(), defc,
|
||||
@ -755,7 +755,7 @@ Handle MethodHandles::resolve_MemberName(Handle mname, KlassHandle caller, TRAPS
|
||||
{
|
||||
assert(!HAS_PENDING_EXCEPTION, "");
|
||||
if (name == vmSymbols::object_initializer_name()) {
|
||||
LinkResolver::resolve_special_call(result, link_info, THREAD);
|
||||
LinkResolver::resolve_special_call(result, Handle(), link_info, THREAD);
|
||||
} else {
|
||||
break; // will throw after end of switch
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ void JavaCalls::call_virtual(JavaValue* result, Handle receiver, KlassHandle spe
|
||||
void JavaCalls::call_special(JavaValue* result, KlassHandle klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
|
||||
CallInfo callinfo;
|
||||
LinkInfo link_info(klass, name, signature);
|
||||
LinkResolver::resolve_special_call(callinfo, link_info, CHECK);
|
||||
LinkResolver::resolve_special_call(callinfo, args->receiver(), link_info, CHECK);
|
||||
methodHandle method = callinfo.selected_method();
|
||||
assert(method.not_null(), "should have thrown exception");
|
||||
|
||||
|
@ -59,3 +59,6 @@ external.lib.roots = ../../
|
||||
|
||||
# Use new module options
|
||||
useNewOptions=true
|
||||
|
||||
# Use --patch-module instead of -Xmodule:
|
||||
useNewPatchModule=true
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,7 +36,22 @@ import java.util.zip.CRC32;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
public class TestCRC32 {
|
||||
public static void main(String[] args) {
|
||||
// standard CRC32 polynomial
|
||||
// coefficients in different forms
|
||||
// normal: polyBits = 0x04c11db7 = 0b0000 0100 1100 0001 0001 1101 1011 0111
|
||||
// reversed: polybits = 0xedb88320 = 0b1110 1101 1011 1000 1000 0011 0010 0000
|
||||
// reversed reciprocal polybits = 0x82608edb = 0b1000 0010 0110 0000 1000 1110 1101 1011
|
||||
//
|
||||
// 0 5 9 13 17 21 25 29
|
||||
// | | | | | | | |
|
||||
// reversed shiftL 1 polyBits = 0x1db710641L = 0b1 1101 1011 0111 0001 0000 0110 0100 0001
|
||||
final static long polyBits = (1L<<(32-32)) + (1L<<(32-26)) + (1L<<(32-23)) + (1L<<(32-22))
|
||||
+ (1L<<(32-16)) + (1L<<(32-12)) + (1L<<(32-11)) + (1L<<(32-10))
|
||||
+ (1L<<(32-8)) + (1L<<(32-7)) + (1L<<(32-5)) + (1L<<(32-4))
|
||||
+ (1L<<(32-2)) + (1L<<(32-1)) + (1L<<(32-0));
|
||||
final static long polyBitsShifted = polyBits>>1;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int offset = Integer.getInteger("offset", 0);
|
||||
int msgSize = Integer.getInteger("msgSize", 512);
|
||||
boolean multi = false;
|
||||
@ -65,11 +80,14 @@ public class TestCRC32 {
|
||||
|
||||
byte[] b = initializedBytes(msgSize, offset);
|
||||
|
||||
final long crcReference = update_byteLoop(0, b, offset);
|
||||
|
||||
CRC32 crc0 = new CRC32();
|
||||
CRC32 crc1 = new CRC32();
|
||||
CRC32 crc2 = new CRC32();
|
||||
|
||||
crc0.update(b, offset, msgSize);
|
||||
check(crc0, crcReference);
|
||||
|
||||
System.out.println("-------------------------------------------------------");
|
||||
|
||||
@ -77,27 +95,35 @@ public class TestCRC32 {
|
||||
for (int i = 0; i < warmupIters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
check(crc1, crcReference);
|
||||
}
|
||||
|
||||
/* measure performance */
|
||||
/* check correctness
|
||||
* Do that before measuring performance
|
||||
* to even better heat up involved methods.
|
||||
*/
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
check(crc1, crcReference);
|
||||
}
|
||||
report("CRCs", crc1, crcReference);
|
||||
|
||||
/* measure performance
|
||||
* Don't spoil times with error checking.
|
||||
*/
|
||||
long start = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
}
|
||||
long end = System.nanoTime();
|
||||
|
||||
double total = (double)(end - start)/1e9; // in seconds
|
||||
double thruput = (double)msgSize*iters/1e6/total; // in MB/s
|
||||
System.out.println("CRC32.update(byte[]) runtime = " + total + " seconds");
|
||||
System.out.println("CRC32.update(byte[]) throughput = " + thruput + " MB/s");
|
||||
|
||||
/* check correctness */
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
if (!check(crc0, crc1)) break;
|
||||
}
|
||||
report("CRCs", crc0, crc1);
|
||||
report("CRCs", crc1, crcReference);
|
||||
|
||||
System.out.println("-------------------------------------------------------");
|
||||
|
||||
@ -110,9 +136,24 @@ public class TestCRC32 {
|
||||
crc2.reset();
|
||||
crc2.update(buf);
|
||||
buf.rewind();
|
||||
check(crc2, crcReference);
|
||||
}
|
||||
|
||||
/* measure performance */
|
||||
/* check correctness
|
||||
* Do that before measuring performance
|
||||
* to even better heat up involved methods.
|
||||
*/
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc2.reset();
|
||||
crc2.update(buf);
|
||||
buf.rewind();
|
||||
check(crc2, crcReference);
|
||||
}
|
||||
report("CRCs", crc2, crcReference);
|
||||
|
||||
/* measure performance
|
||||
* Don't spoil times with error checking.
|
||||
*/
|
||||
start = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc2.reset();
|
||||
@ -124,31 +165,57 @@ public class TestCRC32 {
|
||||
thruput = (double)msgSize*iters/1e6/total; // in MB/s
|
||||
System.out.println("CRC32.update(ByteBuffer) runtime = " + total + " seconds");
|
||||
System.out.println("CRC32.update(ByteBuffer) throughput = " + thruput + " MB/s");
|
||||
|
||||
/* check correctness */
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc2.reset();
|
||||
crc2.update(buf);
|
||||
buf.rewind();
|
||||
if (!check(crc0, crc2)) break;
|
||||
}
|
||||
report("CRCs", crc0, crc2);
|
||||
report("CRCs", crc2, crcReference);
|
||||
|
||||
System.out.println("-------------------------------------------------------");
|
||||
}
|
||||
|
||||
private static void report(String s, Checksum crc0, Checksum crc1) {
|
||||
System.out.printf("%s: crc0 = %08x, crc1 = %08x\n",
|
||||
s, crc0.getValue(), crc1.getValue());
|
||||
// Just a loop over a byte array, updating the CRC byte by byte.
|
||||
public static long update_byteLoop(long crc, byte[] buf, int offset) {
|
||||
return update_byteLoop(crc, buf, offset, buf.length-offset);
|
||||
}
|
||||
|
||||
private static boolean check(Checksum crc0, Checksum crc1) {
|
||||
if (crc0.getValue() != crc1.getValue()) {
|
||||
System.err.printf("ERROR: crc0 = %08x, crc1 = %08x\n",
|
||||
crc0.getValue(), crc1.getValue());
|
||||
return false;
|
||||
// Just a loop over a byte array, with given length, updating the CRC byte by byte.
|
||||
public static long update_byteLoop(long crc, byte[] buf, int offset, int length) {
|
||||
int end = length+offset;
|
||||
for (int i = offset; i < end; i++) {
|
||||
crc = update_singlebyte(crc, polyBitsShifted, buf[i]);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// Straight-forward implementation of CRC update by one byte.
|
||||
// We use this very basic implementation to calculate reference
|
||||
// results. It is necessary to have full control over how the
|
||||
// reference results are calculated. It is not sufficient to rely
|
||||
// on the interpreter (or c1, or c2) to do the right thing.
|
||||
public static long update_singlebyte(long crc, long polynomial, int val) {
|
||||
crc = (crc ^ -1L) & 0x00000000ffffffffL; // use 1's complement of crc
|
||||
crc = crc ^ (val&0xff); // XOR in next byte from stream
|
||||
for (int i = 0; i < 8; i++) {
|
||||
boolean bitset = (crc & 0x01L) != 0;
|
||||
|
||||
crc = crc>>1;
|
||||
if (bitset) {
|
||||
crc = crc ^ polynomial;
|
||||
crc = crc & 0x00000000ffffffffL;
|
||||
}
|
||||
}
|
||||
crc = (crc ^ -1L) & 0x00000000ffffffffL; // revert taking 1's complement
|
||||
return crc;
|
||||
}
|
||||
|
||||
private static void report(String s, Checksum crc, long crcReference) {
|
||||
System.out.printf("%s: crc = %08x, crcReference = %08x\n",
|
||||
s, crc.getValue(), crcReference);
|
||||
}
|
||||
|
||||
private static void check(Checksum crc, long crcReference) throws Exception {
|
||||
if (crc.getValue() != crcReference) {
|
||||
System.err.printf("ERROR: crc = %08x, crcReference = %08x\n",
|
||||
crc.getValue(), crcReference);
|
||||
throw new Exception("TestCRC32 Error");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static byte[] initializedBytes(int M, int offset) {
|
||||
@ -162,7 +229,7 @@ public class TestCRC32 {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static void test_multi(int iters) {
|
||||
private static void test_multi(int iters) throws Exception {
|
||||
int len1 = 8; // the 8B/iteration loop
|
||||
int len2 = 32; // the 32B/iteration loop
|
||||
int len3 = 4096; // the 4KB/iteration loop
|
||||
@ -185,37 +252,31 @@ public class TestCRC32 {
|
||||
(len1+len2+len3)*2+5, (len1+len2+len3)*2+7,
|
||||
(len1+len2+len3)*3, (len1+len2+len3)*3-1, (len1+len2+len3)*3-3,
|
||||
(len1+len2+len3)*3-5, (len1+len2+len3)*3-7 };
|
||||
CRC32[] crc0 = new CRC32[offsets.length*sizes.length];
|
||||
CRC32[] crc1 = new CRC32[offsets.length*sizes.length];
|
||||
long[] crcReference = new long[offsets.length*sizes.length];
|
||||
int i, j, k;
|
||||
|
||||
System.out.printf("testing %d cases ...\n", offsets.length*sizes.length);
|
||||
|
||||
/* set the result from interpreter as reference */
|
||||
// Initialize CRC32 result arrays, CRC32 reference array.
|
||||
// Reference is calculated using a very basic Java implementation.
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
for (j = 0; j < sizes.length; j++) {
|
||||
crc0[i*sizes.length + j] = new CRC32();
|
||||
crc1[i*sizes.length + j] = new CRC32();
|
||||
crc0[i*sizes.length + j].update(b, offsets[i], sizes[j]);
|
||||
crcReference[i*sizes.length + j] = update_byteLoop(0, b, offsets[i], sizes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* warm up the JIT compiler and get result */
|
||||
// Warm up the JIT compiler. Over time, all methods involved will
|
||||
// be executed by the interpreter, then get compiled by c1 and
|
||||
// finally by c2. Each calculated CRC value must, in each iteration,
|
||||
// be equal to the precalculated reference value for the test to pass.
|
||||
for (k = 0; k < iters; k++) {
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
for (j = 0; j < sizes.length; j++) {
|
||||
crc1[i*sizes.length + j].reset();
|
||||
crc1[i*sizes.length + j].update(b, offsets[i], sizes[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check correctness */
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
for (j = 0; j < sizes.length; j++) {
|
||||
if (!check(crc0[i*sizes.length + j], crc1[i*sizes.length + j])) {
|
||||
System.out.printf("offsets[%d] = %d", i, offsets[i]);
|
||||
System.out.printf("\tsizes[%d] = %d\n", j, sizes[j]);
|
||||
check(crc1[i*sizes.length + j], crcReference[i*sizes.length + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,7 +36,23 @@ import java.util.zip.CRC32C;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
public class TestCRC32C {
|
||||
public static void main(String[] args) {
|
||||
// CRC32C (Castagnoli) polynomial
|
||||
// coefficients in different forms
|
||||
// normal: polyBits = 0x1edc6f41 = 0b0001 1110 1101 1100 0110 1111 0100 0001
|
||||
// reversed: polybits = 0x82f63b78 = 0b1000 0010 1111 0110 0011 1011 0111 1000
|
||||
// reversed reciprocal polybits = 0x8f6e37a0 = 0b1000 1111 0110 1110 0011 0111 1010 0000
|
||||
//
|
||||
// 0 5 9 13 17 21 25 29
|
||||
// | | | | | | | |
|
||||
// reversed shiftL 1 polyBits = 0x105ec76f1L = 0b1 0000 0101 1110 1100 0111 0110 1111 0001
|
||||
final static long polyBits = (1L<<(32-32)) + (1L<<(32-28)) + (1L<<(32-27))
|
||||
+ (1L<<(32-26)) + (1L<<(32-25)) + (1L<<(32-23)) + (1L<<(32-22))
|
||||
+ (1L<<(32-20)) + (1L<<(32-19)) + (1L<<(32-18)) + (1L<<(32-14))
|
||||
+ (1L<<(32-13)) + (1L<<(32-11)) + (1L<<(32-10)) + (1L<<(32-9))
|
||||
+ (1L<<(32-8)) + (1L<<(32-6)) + (1L<<(32-0));
|
||||
final static long polyBitsShifted = polyBits>>1;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
int offset = Integer.getInteger("offset", 0);
|
||||
int msgSize = Integer.getInteger("msgSize", 512);
|
||||
boolean multi = false;
|
||||
@ -65,11 +81,14 @@ public class TestCRC32C {
|
||||
|
||||
byte[] b = initializedBytes(msgSize, offset);
|
||||
|
||||
final long crcReference = update_byteLoop(0, b, offset);
|
||||
|
||||
CRC32C crc0 = new CRC32C();
|
||||
CRC32C crc1 = new CRC32C();
|
||||
CRC32C crc2 = new CRC32C();
|
||||
|
||||
crc0.update(b, offset, msgSize);
|
||||
check(crc0, crcReference);
|
||||
|
||||
System.out.println("-------------------------------------------------------");
|
||||
|
||||
@ -77,27 +96,35 @@ public class TestCRC32C {
|
||||
for (int i = 0; i < warmupIters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
check(crc1, crcReference);
|
||||
}
|
||||
|
||||
/* measure performance */
|
||||
/* check correctness
|
||||
* Do that before measuring performance
|
||||
* to even better heat up involved methods.
|
||||
*/
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
check(crc1, crcReference);
|
||||
}
|
||||
report("CRCs", crc1, crcReference);
|
||||
|
||||
/* measure performance
|
||||
* Don't spoil times with error checking.
|
||||
*/
|
||||
long start = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
}
|
||||
long end = System.nanoTime();
|
||||
|
||||
double total = (double)(end - start)/1e9; // in seconds
|
||||
double thruput = (double)msgSize*iters/1e6/total; // in MB/s
|
||||
System.out.println("CRC32C.update(byte[]) runtime = " + total + " seconds");
|
||||
System.out.println("CRC32C.update(byte[]) throughput = " + thruput + " MB/s");
|
||||
|
||||
/* check correctness */
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc1.reset();
|
||||
crc1.update(b, offset, msgSize);
|
||||
if (!check(crc0, crc1)) break;
|
||||
}
|
||||
report("CRCs", crc0, crc1);
|
||||
report("CRCs", crc1, crcReference);
|
||||
|
||||
System.out.println("-------------------------------------------------------");
|
||||
|
||||
@ -110,9 +137,24 @@ public class TestCRC32C {
|
||||
crc2.reset();
|
||||
crc2.update(buf);
|
||||
buf.rewind();
|
||||
check(crc2, crcReference);
|
||||
}
|
||||
|
||||
/* measure performance */
|
||||
/* check correctness
|
||||
* Do that before measuring performance
|
||||
* to even better heat up involved methods.
|
||||
*/
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc2.reset();
|
||||
crc2.update(buf);
|
||||
buf.rewind();
|
||||
check(crc2, crcReference);
|
||||
}
|
||||
report("CRCs", crc2, crcReference);
|
||||
|
||||
/* measure performance
|
||||
* Don't spoil times with error checking.
|
||||
*/
|
||||
start = System.nanoTime();
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc2.reset();
|
||||
@ -124,31 +166,57 @@ public class TestCRC32C {
|
||||
thruput = (double)msgSize*iters/1e6/total; // in MB/s
|
||||
System.out.println("CRC32C.update(ByteBuffer) runtime = " + total + " seconds");
|
||||
System.out.println("CRC32C.update(ByteBuffer) throughput = " + thruput + " MB/s");
|
||||
|
||||
/* check correctness */
|
||||
for (int i = 0; i < iters; i++) {
|
||||
crc2.reset();
|
||||
crc2.update(buf);
|
||||
buf.rewind();
|
||||
if (!check(crc0, crc2)) break;
|
||||
}
|
||||
report("CRCs", crc0, crc2);
|
||||
report("CRCs", crc2, crcReference);
|
||||
|
||||
System.out.println("-------------------------------------------------------");
|
||||
}
|
||||
|
||||
private static void report(String s, Checksum crc0, Checksum crc1) {
|
||||
System.out.printf("%s: crc0 = %08x, crc1 = %08x\n",
|
||||
s, crc0.getValue(), crc1.getValue());
|
||||
// Just a loop over a byte array, updating the CRC byte by byte.
|
||||
public static long update_byteLoop(long crc, byte[] buf, int offset) {
|
||||
return update_byteLoop(crc, buf, offset, buf.length-offset);
|
||||
}
|
||||
|
||||
private static boolean check(Checksum crc0, Checksum crc1) {
|
||||
if (crc0.getValue() != crc1.getValue()) {
|
||||
System.err.printf("ERROR: crc0 = %08x, crc1 = %08x\n",
|
||||
crc0.getValue(), crc1.getValue());
|
||||
return false;
|
||||
// Just a loop over a byte array, with given length, updating the CRC byte by byte.
|
||||
public static long update_byteLoop(long crc, byte[] buf, int offset, int length) {
|
||||
int end = length+offset;
|
||||
for (int i = offset; i < end; i++) {
|
||||
crc = update_singlebyte(crc, polyBitsShifted, buf[i]);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
// Straight-forward implementation of CRC update by one byte.
|
||||
// We use this very basic implementation to calculate reference
|
||||
// results. It is necessary to have full control over how the
|
||||
// reference results are calculated. It is not sufficient to rely
|
||||
// on the interpreter (or c1, or c2) to do the right thing.
|
||||
public static long update_singlebyte(long crc, long polynomial, int val) {
|
||||
crc = (crc ^ -1L) & 0x00000000ffffffffL; // use 1's complement of crc
|
||||
crc = crc ^ (val&0xff); // XOR in next byte from stream
|
||||
for (int i = 0; i < 8; i++) {
|
||||
boolean bitset = (crc & 0x01L) != 0;
|
||||
|
||||
crc = crc>>1;
|
||||
if (bitset) {
|
||||
crc = crc ^ polynomial;
|
||||
crc = crc & 0x00000000ffffffffL;
|
||||
}
|
||||
}
|
||||
crc = (crc ^ -1L) & 0x00000000ffffffffL; // revert taking 1's complement
|
||||
return crc;
|
||||
}
|
||||
|
||||
private static void report(String s, Checksum crc, long crcReference) {
|
||||
System.out.printf("%s: crc = %08x, crcReference = %08x\n",
|
||||
s, crc.getValue(), crcReference);
|
||||
}
|
||||
|
||||
private static void check(Checksum crc, long crcReference) throws Exception {
|
||||
if (crc.getValue() != crcReference) {
|
||||
System.err.printf("ERROR: crc = %08x, crcReference = %08x\n",
|
||||
crc.getValue(), crcReference);
|
||||
throw new Exception("TestCRC32C Error");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static byte[] initializedBytes(int M, int offset) {
|
||||
@ -162,7 +230,7 @@ public class TestCRC32C {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private static void test_multi(int iters) {
|
||||
private static void test_multi(int iters) throws Exception {
|
||||
int len1 = 8; // the 8B/iteration loop
|
||||
int len2 = 32; // the 32B/iteration loop
|
||||
int len3 = 4096; // the 4KB/iteration loop
|
||||
@ -185,37 +253,31 @@ public class TestCRC32C {
|
||||
(len1+len2+len3)*2+5, (len1+len2+len3)*2+7,
|
||||
(len1+len2+len3)*3, (len1+len2+len3)*3-1, (len1+len2+len3)*3-3,
|
||||
(len1+len2+len3)*3-5, (len1+len2+len3)*3-7 };
|
||||
CRC32C[] crc0 = new CRC32C[offsets.length*sizes.length];
|
||||
CRC32C[] crc1 = new CRC32C[offsets.length*sizes.length];
|
||||
long[] crcReference = new long[offsets.length*sizes.length];
|
||||
int i, j, k;
|
||||
|
||||
System.out.printf("testing %d cases ...\n", offsets.length*sizes.length);
|
||||
|
||||
/* set the result from interpreter as reference */
|
||||
// Initialize CRC32C result arrays, CRC32C reference array.
|
||||
// Reference is calculated using a very basic Java implementation.
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
for (j = 0; j < sizes.length; j++) {
|
||||
crc0[i*sizes.length + j] = new CRC32C();
|
||||
crc1[i*sizes.length + j] = new CRC32C();
|
||||
crc0[i*sizes.length + j].update(b, offsets[i], sizes[j]);
|
||||
crcReference[i*sizes.length + j] = update_byteLoop(0, b, offsets[i], sizes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
/* warm up the JIT compiler and get result */
|
||||
// Warm up the JIT compiler. Over time, all methods involved will
|
||||
// be executed by the interpreter, then get compiled by c1 and
|
||||
// finally by c2. Each calculated CRC value must, in each iteration,
|
||||
// be equal to the precalculated reference value for the test to pass.
|
||||
for (k = 0; k < iters; k++) {
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
for (j = 0; j < sizes.length; j++) {
|
||||
crc1[i*sizes.length + j].reset();
|
||||
crc1[i*sizes.length + j].update(b, offsets[i], sizes[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check correctness */
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
for (j = 0; j < sizes.length; j++) {
|
||||
if (!check(crc0[i*sizes.length + j], crc1[i*sizes.length + j])) {
|
||||
System.out.printf("offsets[%d] = %d", i, offsets[i]);
|
||||
System.out.printf("\tsizes[%d] = %d\n", j, sizes[j]);
|
||||
check(crc1[i*sizes.length + j], crcReference[i*sizes.length + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
71
hotspot/test/compiler/unsafe/TestRawAliasing.java
Normal file
71
hotspot/test/compiler/unsafe/TestRawAliasing.java
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8178047
|
||||
* @run main/othervm -XX:CompileCommand=exclude,*.main -XX:-TieredCompilation -XX:-BackgroundCompilation compiler.unsafe.TestRawAliasing
|
||||
* @modules java.base/jdk.internal.misc:+open
|
||||
*/
|
||||
|
||||
package compiler.unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class TestRawAliasing {
|
||||
static private final jdk.internal.misc.Unsafe UNSAFE;
|
||||
static {
|
||||
try {
|
||||
Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
f.setAccessible(true);
|
||||
UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to get Unsafe instance.", e);
|
||||
}
|
||||
}
|
||||
|
||||
static private final int OFFSET_X = 50;
|
||||
static private final int OFFSET_Y = 100;
|
||||
|
||||
private static int test(long base_plus_offset_x, long base_plus_offset_y, int magic_value) {
|
||||
// write 0 to a location
|
||||
UNSAFE.putByte(base_plus_offset_x - OFFSET_X, (byte)0);
|
||||
// write unfoldable value to really the same location with another base
|
||||
UNSAFE.putByte(base_plus_offset_y - OFFSET_Y, (byte)magic_value);
|
||||
// read the value back, should be equal to "unfoldable_value"
|
||||
return UNSAFE.getByte(base_plus_offset_x - OFFSET_X);
|
||||
}
|
||||
|
||||
private static final int OFF_HEAP_AREA_SIZE = 128;
|
||||
private static final byte MAGIC = 123;
|
||||
|
||||
// main is excluded from compilation since we don't want the test method to inline and make base values fold
|
||||
public static void main(String... args) {
|
||||
long base = UNSAFE.allocateMemory(OFF_HEAP_AREA_SIZE);
|
||||
for (int i = 0; i < 100_000; i++) {
|
||||
if (test(base + OFFSET_X, base + OFFSET_Y, MAGIC) != MAGIC) {
|
||||
throw new RuntimeException("Unexpected magic value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user