8142968: Module System implementation

Initial integration of JEP 200, JEP 260, JEP 261, and JEP 282

Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com>
Co-authored-by: Mandy Chung <mandy.chung@oracle.com>
Co-authored-by: Mark Reinhold <mark.reinhold@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Lois Foltan <lois.foltan@oracle.com>
Co-authored-by: Calvin Cheung <calvin.cheung@oracle.com>
Co-authored-by: Christian Tornqvist <christian.tornqvist@oracle.com>
Co-authored-by: Erik Joelsson <erik.joelsson@oracle.com>
Co-authored-by: George Triantafillou <george.triantafillou@oracle.com>
Co-authored-by: Igor Ignatyev <igor.ignatyev@oracle.com>
Co-authored-by: Ioi Lam <ioi.lam@oracle.com>
Co-authored-by: James Laskey <james.laskey@oracle.com>
Co-authored-by: Jean-Francois Denise <jean-francois.denise@oracle.com>
Co-authored-by: Jiangli Zhou <jiangli.zhou@oracle.com>
Co-authored-by: Markus Gronlund <markus.gronlund@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Staffan Larsen <staffan.larsen@oracle.com>
Co-authored-by: Sundararajan Athijegannathan <sundararajan.athijegannathan@oracle.com>
Reviewed-by: acorn, ccheung, coleenp, ctornqvi, dholmes, dsimms, gtriantafill, iklam, jiangli, mgronlun, mseledtsov, cjplummer, sspitsyn, stefank, twisti, hseigel, lfoltan, alanb, mchung, dfazunen
This commit is contained in:
Alan Bateman 2016-03-17 19:04:01 +00:00
parent 007b0fa3db
commit f30fc1c88b
297 changed files with 15848 additions and 2302 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verificationType.hpp"
@ -103,8 +104,6 @@
#define JAVA_9_VERSION 53
enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream,
ConstantPool* cp,
const int length,
@ -1965,7 +1964,7 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
const vmSymbols::SID sid = vmSymbols::find_sid(name);
// Privileged code can use all annotations. Other code silently drops some.
const bool privileged = loader_data->is_the_null_class_loader_data() ||
loader_data->is_ext_class_loader_data() ||
loader_data->is_platform_class_loader_data() ||
loader_data->is_anonymous();
switch (sid) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): {
@ -4358,17 +4357,29 @@ static Array<Klass*>* compute_transitive_interfaces(const InstanceKlass* super,
static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
assert(this_klass != NULL, "invariant");
const Klass* const super = this_klass->super();
if ((super != NULL) &&
(!Reflection::verify_class_access(this_klass, super, false))) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s cannot access its superclass %s",
this_klass->external_name(),
super->external_name()
);
return;
if (super != NULL) {
Reflection::VerifyClassAccessResults vca_result =
Reflection::verify_class_access(this_klass, super, false);
if (vca_result != Reflection::ACCESS_OK) {
ResourceMark rm(THREAD);
char* msg = Reflection::verify_class_access_msg(this_klass, super, vca_result);
if (msg == NULL) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s cannot access its superclass %s",
this_klass->external_name(),
super->external_name());
} else {
// Add additional message content.
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"superclass access check failed: %s",
msg);
}
}
}
}
@ -4380,16 +4391,26 @@ static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS)
for (int i = lng - 1; i >= 0; i--) {
Klass* const k = local_interfaces->at(i);
assert (k != NULL && k->is_interface(), "invalid interface");
if (!Reflection::verify_class_access(this_klass, k, false)) {
Reflection::VerifyClassAccessResults vca_result =
Reflection::verify_class_access(this_klass, k, false);
if (vca_result != Reflection::ACCESS_OK) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s cannot access its superinterface %s",
this_klass->external_name(),
k->external_name()
);
return;
char* msg = Reflection::verify_class_access_msg(this_klass, k, vca_result);
if (msg == NULL) {
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"class %s cannot access its superinterface %s",
this_klass->external_name(),
k->external_name());
} else {
// Add additional message content.
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"superinterface check failed: %s",
msg);
}
}
}
}
@ -4489,12 +4510,14 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
const bool is_super = (flags & JVM_ACC_SUPER) != 0;
const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0;
const bool is_module_info= (flags & JVM_ACC_MODULE) != 0;
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
if ((is_abstract && is_final) ||
(is_interface && !is_abstract) ||
(is_interface && major_gte_15 && (is_super || is_enum)) ||
(!is_interface && major_gte_15 && is_annotation)) {
(!is_interface && major_gte_15 && is_annotation) ||
is_module_info) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@ -4650,65 +4673,9 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer,
int length,
TRAPS) const {
assert(_need_verify, "only called when _need_verify is true");
int i = 0;
const int count = length >> 2;
for (int k=0; k<count; k++) {
unsigned char b0 = buffer[i];
unsigned char b1 = buffer[i+1];
unsigned char b2 = buffer[i+2];
unsigned char b3 = buffer[i+3];
// For an unsigned char v,
// (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
// (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128.
const unsigned char res = b0 | b0 - 1 |
b1 | b1 - 1 |
b2 | b2 - 1 |
b3 | b3 - 1;
if (res >= 128) break;
i += 4;
if (!UTF8::is_legal_utf8(buffer, length, _major_version <= 47)) {
classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
}
for(; i < length; i++) {
unsigned short c;
// no embedded zeros
guarantee_property((buffer[i] != 0), "Illegal UTF8 string in constant pool in class file %s", CHECK);
if(buffer[i] < 128) {
continue;
}
if ((i + 5) < length) { // see if it's legal supplementary character
if (UTF8::is_supplementary_character(&buffer[i])) {
c = UTF8::get_supplementary_character(&buffer[i]);
i += 5;
continue;
}
}
switch (buffer[i] >> 4) {
default: break;
case 0x8: case 0x9: case 0xA: case 0xB: case 0xF:
classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
case 0xC: case 0xD: // 110xxxxx 10xxxxxx
c = (buffer[i] & 0x1F) << 6;
i++;
if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) {
c += buffer[i] & 0x3F;
if (_major_version <= 47 || c == 0 || c >= 0x80) {
// for classes with major > 47, c must a null or a character in its shortest form
break;
}
}
classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx
c = (buffer[i] & 0xF) << 12;
i += 2;
if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) {
c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F);
if (_major_version <= 47 || c >= 0x800) {
// for classes with major > 47, c must be in its shortest form
break;
}
}
classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK);
} // end of switch
} // end of for
}
// Unqualified names may not contain the characters '.', ';', '[', or '/'.
@ -4716,24 +4683,35 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer,
// or <clinit>. Note that method names may not be <init> or <clinit> in this
// method. Because these names have been checked as special cases before
// calling this method in verify_legal_method_name.
static bool verify_unqualified_name(const char* name,
unsigned int length,
int type) {
//
// This method is also called from the modular system APIs in modules.cpp
// to verify the validity of module and package names.
bool ClassFileParser::verify_unqualified_name(const char* name,
unsigned int length,
int type) {
for (const char* p = name; p != name + length;) {
jchar ch = *p;
if (ch < 128) {
p++;
if (ch == '.' || ch == ';' || ch == '[') {
if (ch == '.') {
// permit '.' in module names unless it's the first char, or
// preceding char is also a '.', or last char is a '.'.
if ((type != ClassFileParser::LegalModule) ||
(p == name) || (*(p-1) == '.') ||
(p == name + length - 1)) {
return false;
}
}
if (ch == ';' || ch == '[' ) {
return false; // do not permit '.', ';', or '['
}
if (type != LegalClass && ch == '/') {
if (type != ClassFileParser::LegalClass && ch == '/') {
return false; // do not permit '/' unless it's class name
}
if (type == LegalMethod && (ch == '<' || ch == '>')) {
if (type == ClassFileParser::LegalMethod && (ch == '<' || ch == '>')) {
return false; // do not permit '<' or '>' in method names
}
}
else {
p++;
} else {
char* tmp_p = UTF8::next(p, &ch);
p = tmp_p;
}
@ -5192,7 +5170,7 @@ static void check_methods_for_intrinsics(const InstanceKlass* ik,
}
}
InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) {
InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) {
if (_klass != NULL) {
return _klass;
}
@ -5200,14 +5178,14 @@ InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) {
InstanceKlass* const ik =
InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
fill_instance_klass(ik, CHECK_NULL);
fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);
assert(_klass == ik, "invariant");
return ik;
}
void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
assert(ik != NULL, "invariant");
set_klass_to_deallocate(ik);
@ -5272,6 +5250,12 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
ik->set_host_klass(_host_klass);
}
// Set PackageEntry for this_klass
oop cl = ik->class_loader();
Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl));
ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh());
ik->set_package(cld, CHECK);
const Array<Method*>* const methods = ik->methods();
assert(methods != NULL, "invariant");
const int methods_len = methods->length();
@ -5327,10 +5311,18 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
}
}
// Obtain this_klass' module entry
ModuleEntry* module_entry = ik->module();
assert(module_entry != NULL, "module_entry should always be set");
// Obtain java.lang.reflect.Module
Handle module_handle(THREAD, JNIHandles::resolve(module_entry->module()));
// Allocate mirror and initialize static fields
// The create_mirror() call will also call compute_modifiers()
java_lang_Class::create_mirror(ik,
_loader_data->class_loader(),
module_handle,
_protection_domain,
CHECK);
@ -5344,6 +5336,15 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
CHECK);
}
// Add read edges to the unnamed modules of the bootstrap and app class loaders.
if (changed_by_loadhook && !module_handle.is_null() && module_entry->is_named() &&
!module_entry->has_default_read_edges()) {
if (!module_entry->set_has_default_read_edges()) {
// We won a potential race
JvmtiExport::add_default_read_edges(module_handle, THREAD);
}
}
// Update the loader_data graph.
record_defined_class_dependencies(ik, CHECK);
@ -5351,11 +5352,24 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
if (!is_internal()) {
if (log_is_enabled(Info, classload)) {
ik->print_loading_log(LogLevel::Info, _loader_data, _stream);
}
// No 'else' here as logging levels are not mutually exclusive
if (log_is_enabled(Debug, classload)) {
ik->print_loading_log(LogLevel::Debug, _loader_data, _stream);
ResourceMark rm;
const char* module_name = NULL;
static const size_t modules_image_name_len = strlen(MODULES_IMAGE_NAME);
size_t stream_len = strlen(_stream->source());
// See if _stream->source() ends in "modules"
if (module_entry->is_named() && modules_image_name_len < stream_len &&
(strncmp(_stream->source() + stream_len - modules_image_name_len,
MODULES_IMAGE_NAME, modules_image_name_len) == 0)) {
module_name = module_entry->name()->as_C_string();
}
if (log_is_enabled(Info, classload)) {
ik->print_loading_log(LogLevel::Info, _loader_data, module_name, _stream);
}
// No 'else' here as logging levels are not mutually exclusive
if (log_is_enabled(Debug, classload)) {
ik->print_loading_log(LogLevel::Debug, _loader_data, module_name, _stream);
}
}
if (log_is_enabled(Info, classresolve)) {